SpringMVC+MyBatis declarative transaction management

  • 2020-04-01 04:05:54
  • OfStack

The basic construction environment adopted: SpringMVC, MyBatis, MySQL, tomcat              Spring's transaction management of decomposition of the traditional global transaction management and the disadvantage of local transaction management, make all can use in any environment affairs management model of unity, you can write code at a time, and then in a different environment from inside your code configuration different transaction management strategies, Spring provides two kinds of transaction management strategies: one is declarative transaction management strategy, the other is a programmatic transaction management strategy, here introduces declarative transaction management strategy Since SpringMVC and MyBatis are adopted, annotations are adopted to declare Service and Controller
Since the order of loading the configuration file when the server starts is web.xml-- root-context.xml(the configuration file of Spring)-- servlet-context.xml(the configuration file of SpringMVC), the Controller in the root-context.xml configuration file will be equipped with advanced line scan, but the service has not been enhanced by transaction, so the service will be the original service (without transaction enhancement, Therefore, we must not scan the Controller in root-context.xml. The configuration is as follows:

<!--  Automatically scan the component, and here we're going to put controler The following  controller Remove, they are in spring3-servlet.xml If not removed will affect transaction management.   --> 
 <context:component-scan base-package="com.sence"> 
 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />  
 .</context:component-scan> 
 <!--  Automatically scan the component, and here we're going to put controler The following  controller Remove, they are in spring3-servlet.xml If not removed will affect transaction management.   -->
 <context:component-scan base-package="com.sence">
 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> 
 </context:component-scan>
Scan the Controller in servlet-context.xml without scanning the Service, as follows:

<!--  Scan all controller  But not scanning service--> 
 <context:component-scan base-package="com.sence"> 
 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> 
 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> 
 </context:component-scan> 
 <!--  Scan all controller  But not scanning service-->
 <context:component-scan base-package="com.sence">
 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
 </context:component-scan>
Now you can configure declarative transaction management as follows:

<!-- transaction manager, use DataSourceTransactionManager --> 
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
 <property name="dataSource" ref="dataSource" /> 
 </bean> 
 <!-- spring declarative transaction management --> 
 <aop:config> 
 <aop:pointcut id="fooServiceMethods"  
 expression="execution(* com.sence.*.service.impl.*.*(..))"/>  
 <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>  
 </aop:config> 
 <tx:advice id="txAdvice" transaction-manager="txManager"> 
 <tx:attributes> 
 <tx:method name="find*" read-only="true"/> 
 <tx:method name="load*" read-only="true"/> 
 <tx:method name="*" rollback-for="CustomException"/> 
 </tx:attributes> 
 </tx:advice> 
 <!-- transaction manager, use DataSourceTransactionManager -->
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource" />
 </bean>
 <!-- spring declarative transaction management -->
<aop:config>
 <aop:pointcut id="fooServiceMethods" 
 expression="execution(* com.sence.*.service.impl.*.*(..))"/> 
 <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/> 
 </aop:config>
 <tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
 <tx:method name="find*" read-only="true"/>
 <tx:method name="load*" read-only="true"/>
 <tx:method name="*" rollback-for="CustomException"/>
 </tx:attributes>
 </tx:advice>
At this point, my configuration is complete, but after my test, when I batch add objects to the MySQL database table, when one of the objects has an error, it throws a CustomException transaction but does not roll back, this is really a headache, so I continue to search, the steps are as follows: 1. Look for errors in declarative transaction management, such as a wrong pointcut
2. Find out whether the Controller scans the part of the configuration correctly But I checked on both points, and the transaction didn't roll back. At this point, I had no choice but to use the ultimate weapon: View the source code, to start the debug program, found into the transaction, and the exception, into the rollback procedure after capture, but no rollback database, in order to avoid the interference of Spring's own AbstractPlatformTransactionManager, my own custom made a transaction management classes and inheritance in the configuration file DataSourceTransactionManager class, so that we can clearly see the path of the program, continue to debug, or abnormal, Into the rollback procedure after capture, but no rollback database, at the moment I began to doubt the MySQL database transaction support function, so online search MySQL support for transaction, find MySQL4.0 later can support transactions, but there are two types of MySQL data table, one kind is the traditional data table, another kind is the data table support transactions. There are two types of tables that support transactions: InnoDB and BerkeleyDB Use the following command: show create table ***  Looking at the properties of my database table, I found that my table was of traditional type, so I used navicat to change the table type to: InnoDB, and then ran the program to find that the transaction was rolled back Here is the SpringMVC declarative transaction management configuration complete and running correctly

Related articles: