【问题标题】:Hibernate calls flush on find- causes not-null errorHibernate 调用 flush on find- 导致非空错误
【发布时间】:2023-03-09 16:42:01
【问题描述】:

我有一个将树更新到数据库的过程,并在此过程中执行读取以检查重复实体。

我发现在此过程中途尝试执行 criteria.uniqueResult() 会导致以下错误:

org.hibernate.PropertyValueException: 非空属性引用空或 瞬态值

挖掘堆栈跟踪,我看到 uniqueResult() 正在刷新会话,尝试执行尚未准备好进入数据库的更新。

at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1589)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:306)
at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:328)
at com.inversion.dal.BaseDAO.findUniqueByCriterion(BaseDAO.java:59)

我这里设置错了吗?

非常感谢任何帮助。

马蒂

【问题讨论】:

    标签: java hibernate transactions


    【解决方案1】:

    hibernate 记住需要保存的对象。发出选择时,休眠将刷新这些更改。这确保了选择将返回正确的结果。

    将flushmode 设置为FlushMode.AUTO 以外的任何值都会阻止这种行为。但是错误在您的代码中,您将不完整的对象传递给休眠以保持或更新。所以正确的解决方案是稍后将对象传递给休眠,当它完成时。

    【讨论】:

    • 虽然将不完整的对象传递给休眠是违反空约束的良好候选者,但有很多代码路径可能会触发此类错误,这与会话中已经存在的项目的修改有关,因此错误发生的位置并不总是很明显。
    【解决方案2】:

    关闭 Session 对象的自动刷新以修复此异常。

    Session s;
    // if you're doing transactional work
    s.setFlushMode(FlushMode.COMMIT);
    // if you want to control flushes directly
    s.setFlushMode(FlushMode.MANUAL);
    

    然而,这不是你的错误。代码中较早的部分导致内存中的对象处于无效状态,该状态试图在自动刷新期间持久化到数据库。

    【讨论】:

    • 我正在使用注释来标记事务边界——@Transactional(readOnly=false)。我认为这是处理边界的首选方式,而不是在我的代码中手动处理?此外,实体处于无效状态,但我还没有准备好提交它 - hibernate 在 SELECT 期间自行执行此操作。为什么?
    • 仅仅因为您在事务中并不意味着不会针对数据库执行 SQL。 FlushMode 控制 SQL 何时执行,而不是事务何时提交。如果您要创建就数据库而言具有无效状态的对象,您可能需要按照 Jherico 建议的方式推迟刷新。
    【解决方案3】:

    我已经多次试图弄清这些问题的根源。问题在于很难找到导致问题的根源。

    如果你快要死机了,你还可以在新会话中执行支持查询,例如 findAll

    Domain.withNewSession { session -> ... }
    

    在大多数情况下,这通常可以规避我的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 2015-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多