Grails:未刷新的会话和回滚的事务有什么区别?

时间:2012-03-03 00:12:19

标签: hibernate session grails transactions gorm

我对会话和交易感到困惑。我基本上看不出两者兼而有之,我很困惑何时使用其中一种。

未刷新的会话和未提交的事务有什么区别?

我甚至不知道如何询问我不知道的内容......是否有一个资源可以提供常见会话和交易情况的良好示例,以便我看到差异?

1 个答案:

答案 0 :(得分:20)

Hibernate中的事务与JDBC中的事务几乎完全相同。当您从Connection获得DataSource时,它默认为autocommit = true,因此对于更改为autocommit = false的事务。这样,只有在显式提交时才会在数据库中进行更改,而不是每次进行更新时都会进行更改。

Hibernate的Session做了几件事,但在这种情况下,它的功能是作为第一级缓存。它使用一个名为“事务性写入后备”的概念来提高性能,以便对该缓存中的更改进行排队,并在必要时将它们推送到数据库。因此,例如,如果您检索持久性实例并在复杂的多方法工作流中更改它,其中每个方法可能不做任何更改或几个,则只需要一个更新SQL语句,因此Hibernate会等到必要时将它们聚合在一起。这与您是否在交易中运行无关 - 这总是发生。

会话缓存和活动事务聚合在一起,在活动事务期间刷新。由于Hibernate会尽可能长时间地刷新更改,如果您不在事务中并且刷新,则更改会立即在数据库中持久化。这是一种性能优化,可以减少数据库写入次数。但是,如果您在事务中并刷新会话,则会将更改推送到数据库。但是数据库会保留其事务队列中的更改。因此,即使它们在数据库中,在您提交事务之前,它们也不会被其他连接看到。

理想情况下,不会有任何显式刷新,并且事务提交将在提交之前触发刷新,这将最小化您需要转到数据库的次数并保持对其他调用者不可见的未提交更改。但是你可以根据需要多次冲洗。

会导致Hibernate代表您自动刷新的一件事是查询。正如我所说,你可以对持久化实例进行许多更改(甚至删除它们),它们只会在会话缓存中排队。但是如果您运行查询(动态查找程序,条件,HQL等),Hibernate无法知道排队的更改是否会影响您的查询。所以它是悲观的,并且要确保一切都与查询一致。数据库将使用已刷新但未提交的查询数据并返回预期结果。这就是我们建议您在自定义域类验证器中执行查询时使用withNewSession方法的原因,这样您就不会在验证期间导致当前会话的刷新,从而导致奇怪的行为。