java Spring @Transactional 在每个服务方法的末尾提交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28758452/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring @Transactional commits at the end of each service method
提问by SashikaXP
I have configured a usual declarative transaction management in a Vaadin, Spring project. I have added <tx:annotation-driven transaction-manager="transactionManager" />
in my root-context.xml and all other required maven dependencies in the pom.
My Service methods are annotated with @Transactional
with default propagation.
我在 Vaadin 的 Spring 项目中配置了一个常用的声明式事务管理。我已经<tx:annotation-driven transaction-manager="transactionManager" />
在我的 root-context.xml 和 pom 中添加了所有其他必需的 maven 依赖项。我的服务方法@Transactional
使用默认传播进行了注释。
I want to call two service methods from a method in UI side expecting those two service method to partcipate in a single transaction as the default propagation is PROPAGATION_REQUIRED
. But those two methods are committed to the db independantly. That means if the second method fails, the first one has anyway committed to the db. I have not used try{}catch{{
blocks so any RuntimeException will be bubbled up.
我想从 UI 端的一个方法调用两个服务方法,期望这两个服务方法参与单个事务,因为默认传播是PROPAGATION_REQUIRED
. 但是这两种方法独立地提交给数据库。这意味着如果第二种方法失败,第一种方法无论如何都会提交给数据库。我没有使用try{}catch{{
块,所以任何 RuntimeException 都会冒泡。
The spring logs are attached. Some lines are removed to reduce the #of lines
附上弹簧原木。删除了一些行以减少 #of 行
[qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/getTransaction Creating new transaction with name [...UserServiceImpl.turnOnPwdResetFlag]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/doBegin Switching JDBC Connection [com.jolbox.bonecp.ConnectionHandle@42398a05] to manual commit [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/handleExistingTransaction Participating in existing transaction [qtp187048467-48] DEBUG o.s.jdbc.core.JdbcTemplate/doInStatement SQL update affected 1 rows [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/processCommit Initiating transaction commit [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/doCommit Committing JDBC transaction on Connection [com.jolbox.bonecp.ConnectionHandle@42398a05] [qtp187048467-48] DEBUG o.s.jdbc.datasource.DataSourceUtils/doReleaseConnection Returning JDBC Connection to DataSource ` ` [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/getTransaction Creating new transaction with name [...UserServiceImpl.turnOffPwdResetFlag]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; [qtp187048467-48] DEBUG o.s.j.d.DataSourceTransactionManager/handleExistingTransaction Participating in existing transaction [qtp187048467-48] DEBUG o.s.jdbc.datasource.DataSourceUtils/doReleaseConnection Returning JDBC Connection to DataSource
回答by dunni
If you want to have one transaction for both method calls, you have to make sure, that the method, where the two methods are called, also have the transaction annotation, like this example:
如果您想为两个方法调用使用一个事务,则必须确保调用这两个方法的方法也具有事务注释,如下例所示:
@Transactional
public void callingMethod() {
method1();
method2();
}
@Transactional
public void method1() {
}
@Transactional
public void method2() {
}
回答by SashikaXP
With the help of Spring transaction internals, Open session in view filterI came up with a solution.
在Spring 事务内部机制的帮助下,在视图过滤器中打开会话我想出了一个解决方案。
According to the first link, in a Spring MVC context a transaction is begun in the controller context and the @Transactional
methods in service layer then participates, creates or make another appropriate transaction on top of the already existing transaction. But if the UI layer is something other than Spring MVC this does not happen.
根据第一个链接,在 Spring MVC 上下文中,事务在控制器上下文中开始,@Transactional
然后服务层中的方法参与、创建或在现有事务之上创建另一个适当的事务。但是如果 UI 层不是 Spring MVC,这不会发生。
As shown in this Spring transaction imagethe transaction advisor is the one who takes the decision whether to commit a transaction or mark for rollback. So if we just let a service method proxy to create a transaction where non exists beforehand, at the end of that very proxy method the advisor takes the decision to commit the transaction. To overcome this we have to create a transaction well before the two service method calls, so those two methods will join the transaction rather than committing by them selves.
如这张Spring 事务图像所示,事务顾问是决定是提交事务还是标记回滚的人。因此,如果我们只是让一个服务方法代理来创建一个预先不存在的事务,那么在该代理方法结束时,顾问会做出提交事务的决定。为了克服这个问题,我们必须在两个服务方法调用之前创建一个事务,因此这两个方法将加入事务而不是由它们自己提交。
In Hibernatecontext the Spring MVC supports OpenSessionInView, which creates a transaction per request. What I have done is create a similar servlet filter to create a transaction at the beginning of a request and commits at the end of filter chain. This works perfectly in Vaadin, Spring and JDBC environment. If you are so concerned that a Spring transaction and hence a database connection is acquired on every HTTP request, try using a LazyConnectionDataSourceProxy
.
在Hibernate上下文中,Spring MVC 支持 OpenSessionInView,它为每个请求创建一个事务。我所做的是创建一个类似的 servlet 过滤器,以在请求开始时创建事务并在过滤器链的末尾提交。这在 Vaadin、Spring 和 JDBC 环境中非常有效。如果您非常担心每个 HTTP 请求都会获取 Spring 事务并因此获取数据库连接,请尝试使用LazyConnectionDataSourceProxy
.
See the solution here: I want to... Use JDBC, Spring transactions and @Transactional
请参阅此处的解决方案:我想...使用 JDBC、Spring 事务和@Transactional