【问题标题】:Hibernate Session is invalidated after ConstraintViolationExceptionConstraintViolationException 后 Hibernate Session 失效
【发布时间】:2011-02-24 18:58:46
【问题描述】:

在抛出约束违反异常后,有什么方法可以继续使用线程绑定的休眠会话?我在这里举一个简短的例子:

    Parent other=service.load(33); // loads a new parent
    try {
        Parent p=new Parent();
        p.setName("A name");
        service.save(p); // a @Transactional spring service class, throws ConstraintViolationException - name should be at least 15 characters long
    } catch (ConstraintViolationException e){
        // i would like to handle validation errors and proceed normally
        // but the session is allready closed here
    }
    System.out.println("Children: " + other.getChildren()); // lazy initialization exception, even when using opensessioninview

从现在开始,休眠会话完全没用,即使对于只读操作,例如使用 OpenSessionInView 模式在视图中呈现惰性集合也是如此。

【问题讨论】:

    标签: hibernate


    【解决方案1】:

    Session 的文档指出 如果 Session 抛出异常,则必须回滚事务并丢弃会话。发生异常后,Session的内部状态可能与数据库不一致。

    AFAIK,没有办法从中恢复,我记得有人在工作中警告我不要因为这些问题而使用 session-per-request/OpenSessionInView-pattern。

    【讨论】:

    • 这可能是正确的答案,但多么令人不满意!在使用 JPA (Hibernate 3) 和 Spring 的应用程序中,我注意到当我们在合并后显式刷新实体管理器时引发了 ConstraintViolationException 异常,但如果我们删除了刷新,则会引发更通用的 Spring TransactionSystemException,其中包含嵌套的RollbackException 又包含根ConstraintViolationException。但是,在捕获TransactionSystemException 之后,实体管理器(休眠会话)仍然可用。不再有延迟初始化错误!
    • @Brice:考虑到文档明确指出在抛出异常后不要使用 Session,找到一种仍然使用它的解决方法并不会降低它的危险性。它可能适用于某些情况而不适用于其他情况,从而导致不确定的行为。但是,如果它对您没有任何问题,那就太好了!尽管如此,就我个人而言,我宁愿不使用任何这样的“噱头”,而是首先找出事务有什么问题(例如在这个问题中,以其他方式验证输入,而不是为数据库留下验证)。
    • 我同意。更清楚地说,这个问题与 bean 验证(JSR 303)异常(javax.validation.ConstraintViolationException 不是数据库约束异常)有关,导致会话/实体管理器抛出异常,导致自身无用。在 pre-persist/pre-update/pre-remove 验证失败后,如果能够仍然将会话用于只读查询,那就太好了。在这种情况下,数据库级别不会发生任何会导致使用会话危险的事情(据我所知),它只是使某个实体无效的业务规则。
    • 也许,比我上面的花哨解决方案更好的选择是在会话无效时重新创建会话,但我不确定在使用 OpenSessionInView 时如何执行此操作(OpenEntityManagerInView with JPA)模式(例如使用 Spring 提供的 OpenEntityManagerInViewFilter)。
    • @Brice:使用 Spring 时,Transactional-annotation 有一个名为 noRollbackFor (docs.spring.io/spring/docs/3.1.x/javadoc-api/org/…) 的字段,可用于列出在您知道的情况下不应导致回滚的异常类期望它们(例如,在创建新用户时,首先使用应该使用 getSingleResult 返回单个结果的查询检查用户的存在,但最终抛出 NoResultException,添加新用户仍需要事务) .
    【解决方案2】:

    使用 StatelessSession 而不是 Session。这就是诀窍。

    使用 StatelessSession,您可以在任何异常之后继续,因为这在 SQL 中是可能的(即使在一个事务中 - 休眠不会完成提交/回滚)。这是批量更新/插入或检查是否违反唯一约束的理想选择。

    但要注意,StatelessSession 与普通会话相比有很多限制。请参阅 Hibernate 文档/Javadocs。

    【讨论】:

    • 对我来说很好用! (到目前为止)
    • 谢谢。工作。我只需要插入就可以了。
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    相关资源
    最近更新 更多