Java 休眠:flush()和commit()
单独调用Java 休眠:flush()和commit(),java,hibernate,orm,Java,Hibernate,Orm,单独调用org.hibernate.Session.flush()是否是一种好的做法 如org.hibernate.Sessiondocs中所述 必须在工作单元结束时调用,然后提交事务并关闭会话(取决于刷新模式,transaction.commit()调用此方法) 如果org.hibernate.Transaction.commit()已经可以调用flush() Session session = sessionFactory.openSession(); Transaction tx = se
org.hibernate.Session.flush()
是否是一种好的做法
如org.hibernate.Session
docs中所述
必须在工作单元结束时调用,然后提交事务并关闭会话(取决于刷新模式,transaction.commit()调用此方法)
如果
org.hibernate.Transaction.commit()
已经可以调用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();
session.clear();
}
}
tx.commit();
session.close();
Session Session=sessionFactory.openSession();
事务tx=会话.beginTransaction();
对于(int i=0;i<100000;i++){
客户=新客户(…);
session.save(客户);
如果(i%20==0){//20,则与JDBC批处理大小相同
//刷新一批插入并释放内存:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
如果不调用flush方法,一级缓存将抛出OutOfMemoryException
默认情况下,刷新模式是自动的,这意味着:“有时会在执行查询之前刷新会话,以确保查询不会返回过时状态”,但大多数情况下,在提交更改时会刷新会话。当您使用FlushMode=Manual或希望进行某种优化时,手动调用flush方法非常有用。但是我从来没有这样做过,所以我不能给你实际的建议。显式刷新的一个常见情况是,当你创建一个新的持久实体,你希望它有一个人工主键生成并分配给它,以便你以后可以在同一事务中使用它。在这种情况下,调用flush将导致您的实体获得一个id
另一种情况是,如果一级缓存中有很多内容,并且您希望定期将其清除(以减少缓存使用的内存量),但仍然希望将整个内容一起提交。这就是所涉及的情况。flush()代码>
刷新是将底层持久存储与内存中的持久状态同步的过程。它将在正在运行的事务中更新或插入到您的表中,但可能不会提交这些更改
您需要在批处理中刷新,否则可能会
OutOfMemoryException.
Commit()代码>
提交将使数据库提交。当您有一个持久化对象并且更改了该对象上的值时,它会变脏,hibernate需要将这些更改刷新到持久化层。因此,您应该提交,但它也会结束工作单元(transaction.commit()
)。flush()
将数据库与内存中对象的当前状态同步,但不会提交事务。因此,如果调用flush()
后出现异常,则事务将回滚。
您可以使用flush()
将数据库与小数据块同步,而不是使用commit()
立即提交大数据,并面临从内存异常中获取的风险
commit()
将使存储在数据库中的数据永久化。一旦commit()
成功,您就无法回滚事务。session.flush()是一种同步方法,用于按顺序将数据插入数据库。如果使用此方法,数据不会存储在数据库中,但会存储在缓存中,如果中间出现任何异常,我们可以处理它。
但commit()会将数据存储在数据库中,如果我们存储更多的数据,可能会出现内存不足异常,就像在保存点主题的JDBC程序中一样,除非必要,否则通常不建议显式调用flush。Hibernate通常在事务结束时自动调用Flush,我们应该让它完成它的工作。现在,在某些情况下,您可能需要显式调用flush,其中第二个任务取决于第一个持久性任务的结果,这两个任务都在同一事务中
例如,您可能需要持久化一个新实体,然后使用该实体的Id在同一事务中执行其他任务,在这种情况下,需要首先显式刷新该实体
@Transactional
void someServiceMethod(Entity entity){
em.persist(entity);
em.flush() //need to explicitly flush in order to use id in next statement
doSomeThingElse(entity.getId());
}
还请注意,显式刷新不会导致数据库提交,数据库提交仅在事务结束时完成,因此,如果调用刷新后发生任何运行时错误,更改仍将回滚 你能参考一下这篇文章吗?这个答案给出了一个具体的例子,在这个例子中,显式地调用flush是一个好主意,但我不认为它解决了是否应该始终这样做的一般问题。嗨@KorayTugay。我很长一段时间都没有使用新版本hibernate的经验。但是以前如果没有clean,您可能会收到一些意想不到的结果。因此,我建议尝试不同的方法,甚至检查最新的文档。如果您仔细查看,您可以使用@Transactional
注释插入sessionFactory
。从那时起,你不需要你的代码到处都是事务性的(但在某些情况下需要)。我在代码中遇到了一个有趣的情况,我必须合并一个已经从客户端应用程序生成了id的实体,然后刷新同一个实体以获得数据库生成的字段,例如创建和修改日期。如果不调用session.flush(),它会抛出一个object not found异常,因为合并调用有时会被忽略,直到事务结束。当我在合并调用之后添加flush时,它会强制hibernate执行实际查询,然后刷新对象,因为它现在存在于数据库中!如果您想访问生成的PK imme