问题
in "applicationContext-base.xml" I add below:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
>
.....
<!-- transaction support-->
<!-- PlatformTransactionMnager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- enable transaction annotation support -->
<tx:annotation-driven transaction-manager="txManager" />
and I want to setup a transaction to a function in the "controller"
@Controller
@RequestMapping("/ywdata")
public class YwController extends BaseController{
....
@Transactional(timeout=1)
private void submitNewSXSQ(Map map, HttpServletRequest request, HttpServletResponse response) throws Exception {
...//STEP1 :do some db insert and update STEP1
if(true)
throw new Exception("test transaction ");
...//STEP2: do another db insert and update
and I expected the db operation should never be commit since I throw a exception before return. but actually not.
回答1:
There are multiple issues with your code:
@Transactional
on private methods don't work@Transactional
on@Controller
annotated classes usually don't work- rollback is not performed for checked exceptions
The last issue can be easily understood. Let me explain the first two problems. AOP in Spring works like this:
- before the application context is initialized, Spring searches for beans which require method interception
- a special proxy bean is registered for each of these beans... the proxy is either dynamic interface implementation (JDK proxy) or a dynamic subclass (CGLIB proxy) of your target bean
- the proxy replaces the definition of your bean... original definition is renamed and marked as not eligible for autowiring (but it is still present on application context)
- the methods on proxy are very dumb - all they do is interception logic (i.e. calling some aspect before/after/around execution) and calling the original proxied target bean method
Why private methods are problem:
- with JDK proxying (default):
@Transactional
won't work if you have@Transactional
on non-interface method (only interface methods are present on the proxy)
- with CGLIB proxying:
@@Transactional
won't work if you have@Transactional
on private or final method (only non-private and non-final methods can be overridden in dynamic subclass)
And why controllers are problem:
- Spring's
RequestMappingHandlerMapping
(bean responsible for mapping requests to your@Controllers
) asks application context to get all beans with@Controller
annotation- this might return your original class, not the proxy (I think there was a bug for this in Spring JIRA, so it might be already fixed)
- in case of JDK proxying, you need to add the annotation to the interface (so that the proxy is annotated)... this means that you would need to define interfaces for your controllers
What to do:
- I suggest you to move transaction handling to service level
- If you want your transaction to be wrapped around the whole request, you might take your inspiration from OpenSessionInViewFilter.
- Also I encourage you to put breakpoint in your code and check the stack trace and look for the AOP proxy.
- If you still want to manually handle transactions in some random part of code, you can use TransactionTemplate helper class.
回答2:
From Spring documentation, it is the default behavior: Transactions are marked for rollback only for unchecked exceptions.
See section 10.5.3 of doc
来源:https://stackoverflow.com/questions/25012070/spring-managed-transaction-commits-where-it-shouldnt