org.hibernate.Session.flush()
单独打电话是个好习惯吗?
正如org.hibernate.Session
文档中所说,
必须在工作单元结束时调用,在提交事务和关闭会话之前(取决于刷新模式,Transaction.commit() 调用此方法)。
你能解释一下flush()
明确调用的目的org.hibernate.Transaction.commit()
吗?
在 Hibernate Manual 你可以看到这个例子
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();
如果不调用 flush 方法,您的一级缓存将抛出 OutOfMemoryException
flush()
将使您的数据库与内存中保存的对象/对象的当前状态同步,但它不会提交事务。因此,如果您在flush()
调用后遇到任何异常,则事务将回滚。您可以使用小块数据同步您的数据库,flush()
而不是使用一次提交大量数据,commit()
并面临获得OutOfMemoryException
.
commit()
将使存储在数据库中的数据永久化。commit()
一旦成功,您就无法回滚您的事务。
显式刷新的一种常见情况是,当您创建一个新的持久实体并希望它生成并分配一个人工主键,以便您以后可以在同一事务中使用它。在这种情况下,调用 flush 会导致您的实体获得一个 id。
另一种情况是,如果一级缓存中有很多东西,并且您想定期清除它(以减少缓存使用的内存量),但您仍然想将整个东西一起提交. 这就是阿列克谢的回答所涵盖的情况。
flush();
刷新是将底层持久存储与内存中保存的持久状态同步的过程。它将更新或插入正在运行的事务中的表中,但它可能不会提交这些更改。
您需要在批处理中刷新,否则可能会出现 OutOfMemoryException。
Commit();
Commit 将使数据库提交。当你有一个持久化的对象并且你改变了它的一个值时,它会变脏,hibernate 需要将这些更改刷新到你的持久层。因此,您应该提交,但它也结束了工作单元 ( transaction.commit()
)。
通常不建议显式调用flush,除非有必要。Hibernate 通常在事务结束时自动调用 Flush,我们应该让它完成它的工作。现在,在某些情况下,您可能需要显式调用 flush,其中第二个任务取决于第一个 Persistence 任务的结果,两者都在同一个事务中。
例如,您可能需要持久化一个新实体,然后使用该实体的 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());
}
另请注意,显式刷新不会导致数据库提交,数据库提交仅在事务结束时完成,因此如果在调用刷新后发生任何运行时错误,更改仍将回滚。
默认情况下,刷新模式为 AUTO,这意味着:“有时会在查询执行之前刷新会话,以确保查询永远不会返回过时状态”,但大多数情况下,当您提交更改时会刷新会话。当您使用 FlushMode=MANUAL 或想要进行某种优化时,手动调用 flush 方法很有用。但是我从来没有这样做过,所以我不能给你实用的建议。
session.flush() 是同步方法,意思是按顺序向数据库中插入数据。如果我们使用这种方法,数据不会存储在数据库中,而是存储在缓存中,如果中间出现异常我们可以处理。但是 commit() 它将数据存储在数据库中,如果我们存储的数据量更大,那么可能会出现内存异常,就像保存点主题中的 JDBC 程序一样