【问题标题】:How session.flush is helping in memory release here?session.flush 如何在这里帮助释放内存?
【发布时间】:2014-11-13 19:34:05
【问题描述】:

flush docsjava 中所述

刷新是同步底层持久化的过程 存储在内存中的持久状态。

这是我对上述说法的理解

所以如果有人在做 插入/更新然后刷新,额外插入的行将是谎言 仅在 java 内存中。但其他方式即 Db 数据只会是 仅在提交时与内存中保存的持久状态同步。

现在让我们通过以上的理解

我遇到了HIbernate commit() and flush(),接受的答案告诉我 session.flush 在某些情况下有助于释放内存,从而避免 OutOfMemoryException。

当我在下面做时,line1 (session.flush()) 将为客户表上的 20 个客户执行插入查询 释放列表中 20 个客户对象的内存,但另一方面创建 20 个客户数据行 在仍然在java内存中的客户表下(它只会在第2行提交时进入数据库)。所以我不确定 session.flush 如何帮助释放内存?

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();


for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush(); //line1
        session.clear();
    }
}

tx.commit();// line2
session.close();

【问题讨论】:

    标签: java database hibernate


    【解决方案1】:

    flush() 会将数据发送到数据库。如果您在 Hibernate 中激活 SQL 日志记录,您将看到这一点。 commit() 将提交之前发送到数据库的更改。可能是,您的缓存保留了全部或部分数据。在这种情况下,您必须调整缓存设置。

    也就是说,如果您在内存中有太多已更改或新的对象,您需要执行刷新以避免 OutOfmemoryError,那么您可能需要在更深层次上更改您的设计,例如进行多个但较小的事务。拥有这么大的事务可能会给您的应用程序和数据库带来问题。

    【讨论】:

      【解决方案2】:

      根据 API session.flush()

      void flush()
                 throws HibernateException
      

      强制此会话刷新。必须在一个单元的末尾调用 工作,在提交事务和关闭会话之前 (取决于刷新模式,Transaction.commit() 调用此方法)。

      刷新是同步底层持久化的过程 存储在内存中的持久状态。

      因此,此方法的目的是将您的持久状态与底层数据库同步。如果您仍然有对对象的引用,这将无助于释放内存。

      也请参考此链接 - Hibernate out of memory exception while processing large collection of elements

      在您的程序中,您在for-loop 中创建100000 Customer。如果没有休眠代码,则意味着您没有维护这些对象的任何引用,因此它们有资格进行垃圾回收。

      但是当你说session.save(customer) 时,这些对象与 Hibernate 的会话相关联,因此它们将被放置在一级缓存中。

      如果对象的数量增加并且没有足够的内存可用,那么您将遇到内存不足的问题,因为 hibernate 会尝试在内存中维护所有这些对象。所以调用flush方法会让hibernate调用数据库所需的查询,调用clear会帮助它释放一级缓存中的内存,从而释放一些内存。

      更新:

      调用session.clear() 会使休眠状态清除它内部以一级缓存的形式维护的内存。 session.clear() 调用 StatefulPersistenceContext.clear() 并调用 clear() method on various Map's 和其他对象。这会清除一级缓存中的内存。这清楚地表明对象有资格进行有助于释放一些内存的垃圾收集。因此状态不再由 Hibernate 维护,因此对象处于分离状态。

      现在根据 API Traansaction.commit();:

      void commit()
                  throws HibernateException
      

      刷新关联的 Session 并结束工作单元(除非我们是 在 FlushMode.MANUAL 中。

      当且仅当 底层事务由该对象发起。

      调用commit() 会刷新所有待处理的项目,然后将commit 发送到底层数据库。

      更新:

      另请参阅此链接 - Flushing the session,其中明确表示当我们调用 flush() 方法时会进行 JDBC 调用。

      有时 Session 会执行所需的 SQL 语句 将 JDBC 连接的状态与持有的对象的状态同步 在记忆中。这个过程,称为flush。

      除非你明确地flush(),否则绝对不能保证 关于 Session 何时执行 JDBC 调用,只有在 他们被执行。

      【讨论】:

      • @MSach,用更多细节更新了我的答案,请检查是否有帮助。
      • 您说“flush 方法会使休眠状态调用数据库所需的查询”。这就是我的怀疑。它不会调用物理数据库上的所需查询,而是调用 java 内存中保存的数据库表(持久状态)。
      • @MSach,我猜这是不正确的,在我看来,查询是从我看到的日志中发出的。甚至 API 都说 Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory. 这里持久存储代表数据库而不是内存。一旦你调用 clear 然后对象就不再在内存中了。你能提供一些支持你的陈述的链接吗?
      • 所以你的意思是说,flush 使查询被触发到 DB(内部意味着 DB 会话将它保存在某个地方)并且在提交时,它实际上已提交。
      • @MSach,是的,commit就是提交事务。 Session.clear() 是实际清除内存的那个,请参考StatefulPersistenceContext.clear() 的链接(在我的回答中),您可以清楚地看到通过清除各种对象释放了内存,其中一些是 Map 的
      猜你喜欢
      • 2011-03-18
      • 1970-01-01
      • 2011-05-23
      • 2014-04-27
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 2022-11-17
      相关资源
      最近更新 更多