【问题标题】:Hibernate not flushing modified objects to databaseHibernate 不会将修改后的对象刷新到数据库
【发布时间】:2011-04-06 23:49:57
【问题描述】:

我正在处理一个项目,该项目在过去几个月中开发了一个非常烦人的错误,涉及对象更新。在休眠中更新时,某些对象(尤其是用户)永远不会被标记为脏和刷新。例如:

Session session = factory.openSession(interceptor);
Transaction tx = session.beginTransaction();

Object object = session.load(someId);
// Modify object ...
session.update(object);

tx.commit();

session.flush();
session.close();

拦截器上的所有适当方法都被休眠调用,除了 Interceptor.onFlushDirty 和 Interceptor.findDirty。我最初的假设是,当我们将用户对象存储在 http 会话中时,这是分离对象的问题;然而,删除所有分离对象的重构并没有解决问题。

事务肯定会被提交,并且会话正在刷新并在完成时关闭。我还仔细检查以确保会话未处于只读模式。

我也尝试使用 Session.merge 代替 Session.update 无效。使用 Session.merge 时,返回的对象包含正确的更新信息,但数据库永远不会更新。

我发现this SO 问题似乎描述了一个类似的问题(相关,因为我正在处理的对象存储了一个自定义枚举字段)和一个good description of Hibernate's dirty checking mechanism,但除此之外的信息有点稀疏。

我的 cfg.xml 看起来像这样:

<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.default_batch_fetch_size">1024</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.show_sql">false</property>

<property name="hibernate.c3p0.aquire_increment">1</property>
<property name="hibernate.c3p0.initial_pool_size">1</property>
<property name="hibernate.c3p0.min_size">4</property>
<property name="hibernate.c3p0.max_size">32</property>
<property name="hibernate.c3p0.idle_test_period">100</property> <!-- seconds -->
<property name="hibernate.c3p0.timeout">600</property> <!-- seconds -->

<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</property>

<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

<property name="hibernate.jdbc.fetch_size">1024</property>

<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>

<property name="hibernate.search.worker.execution">async</property>
<property name="hibernate.search.default.directory_provider">org.hibernate.search.store.RAMDirectoryProvider</property>
<property name="hibernate.search.default.indexwriter.batch.ram_buffer_size">256</property>
<property name="hibernate.search.default.optimizer.transaction_limit.max">1000</property>

更新:我已尝试禁用和启用 Hibernates 二级缓存,因为 Finbarr 建议无效。

有人对我可能尝试的其他事情有什么建议吗?

【问题讨论】:

    标签: java hibernate


    【解决方案1】:

    尝试禁用休眠的二级缓存。实际上,您可以发布您的 cfg.xml 吗?

    【讨论】:

    • 二级缓存最近才启用,这是之前的问题。
    【解决方案2】:

    Finbarr 部分正确,几乎可以肯定是缓存问题,但不是二级缓存。通过forcing Hibernate 进行更新,无论它是否更改了所有内容,现在都可以正确保存。

    session.evict(object);
    session.update(object);
    

    【讨论】:

      【解决方案3】:

      在我的项目的上下文中,我偶然发现了一段代码,它完成了您上面提到的操作:驱逐然后更新。 您的调查中的其他元素是否对这个问题有更多的见解。有错误还是没有错误 您是否将此行为/错误报告给休眠和/或您是否有该 JIRA 的参考? 你的休眠版本是什么?

      关于潜在原因: -1-您提到了只读会话,但在查询级别或对象级别没有提到只读会话 -2- 您是否检查过对象没有从会话中被逐出(EvictEventListener) -3-您是否检查过对象没有再次更改为其原始状态,因此不需要更新或再次使用对象的旧(分离)版本进行更新调用

      任何意见表示赞赏, 问候, 克里斯托夫

      【讨论】:

      • 如果我仍然在公司工作并且可以访问代码库,我很乐意为您提供意见。
      【解决方案4】:

      问题出在代码中:您是在刷新会话之前提交事务! 您必须刷新将与当前事务“同步”会话状态的会话,然后提交事务:

      Session session = factory.openSession(interceptor);
      Transaction tx = session.beginTransaction();
      
      Object object = session.load(someId);
      // Modify object ...
      session.update(object);
      session.flush();
      
      tx.commit();
      session.close();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-12
        • 2011-09-13
        • 1970-01-01
        • 2018-12-15
        • 2020-09-23
        相关资源
        最近更新 更多