我对使用Hibernate的Spring中的事务传播感到困惑。我在服务层方法上使用Spring @Transactional
注释。有些被标记为'只读=真'。如果我的一个只读服务方法调用的方法不是只读的,我该如何处理?
我想我可以将所有读写方法标记为支持REQUIRES_NEW
传播,但这会导致我可能不想要的行为 - 即我只想在读取的情况下进行新的事务only方法称为读写方法。如果读写方法调用另一个读写方法,我就不需要新的事务。
考虑到所有这些因素,我不明白Open Session In View(OSIV)是如何工作的!当然,在Spring中使用OSIV,OpenSessionInViewFilter
必须在调用服务方法之前启动事务。在这种情况下,必须定义事务是只读还是读写。但是,怎么知道呢?它不知道在服务层的掩护下会发生什么。
我对这一切都完全处于黑暗中,并希望有人向我解释它!
答案 0 :(得分:6)
Hibernate会话的生命周期与事务的生命周期不同。两者可以相互重叠。
在OpenSessionInViewFilter
的情况下,这与事务完全无关,它只是在请求期间管理Hibernate会话的生命周期。调用Spring-transactional方法时,将启动一个新事务,并与hibernate会话关联,然后在方法退出时提交/回滚。然后,当请求完成时,过滤器将关闭会话。没有必要在会话的同时开始/完成交易。
至于你的read-only
交易问题(这是一个完全不同的问题,偶然),这实际上只是对底层数据库提示不会修改任何数据。我从未见过这有任何具体的影响,但它作为一种文档工具似乎比其他任何东西都更有用。
答案 1 :(得分:3)
如果从只读事务方法调用读写事务方法,则只传播只读状态。即整个交易将是只读的。您可能希望将调用方法更改为读写,因为事务应该是读写。
或者您可以使用REQUIRES_NEW传播,但在这种情况下,Spring会在新事务的生命周期内创建另一个会话。仅在真正需要新交易时使用。
Hibernate会话可能包含多个顺序事务。所以OSIV过滤器不需要知道它将包含哪种类型的事务。 OSIV过滤器使用FlushMode = MANUAL创建会话,读写事务方法将临时更改为FlushMode = AUTO。每个事务都将使用只读或读写JDBC连接。
答案 2 :(得分:2)
Open Session In View不要求整个请求发生在单个事务中,它只表示Hibernate Session绑定到服务请求的线程,并在每次要求该请求中的Session时重新使用。请记住,Session就像一个花哨的映射,它维护在其范围内映射的所有对象的标识,实际对象可以在一个事务中或在多个事务中获取。
每个事务的会话模式实际上是OSIV的替代。通常不会遇到这种模式。
关于调用读写方法的只读方法,我会说你应该重新思考为什么你要考虑这个只读,而实际上它可以写数据。我认为要么你将只读部分分解出来并让读写方法调用只读方法,要么你只是停止将其视为只读(它不是)。
仅仅因为事务被置于一个事务的只读模式,并不意味着它将继续处于会话范围的其余部分(OSIV)的只读模式。实际上,在开放会话范围内的后续事务可能甚至不会发生在同一连接上。