第一节讲述了不一样service之间事务的传播,通过小实验,还原了spring的事务传播结论,这期实验下service中开启新线程后,事务如何传播java
首先是controller发起请求:spring
@RequestMapping(value="/test2") public void insert2() { System.out.println("---------spring mvc update---------"); userService.update2(111,"aaaazz"); System.out.println("---------spring mvc all---------"); }
userServiceImplapache
@Override @Transactional public void update2(int id,String username) { System.out.println("---------UserServiceImpl updateAge start---------"); updateAge(id); System.out.println("---------UserServiceImpl updateAge end---------"); MyThread thread = new MyThread(scoreService); thread.start(); // int i = 1 / 0; System.out.println("---------UserServiceImpl method over---------"); }
涉及的内部类:session
class MyThread extends Thread{ IScoreService scoreService; public MyThread (IScoreService scoreService){ this.scoreService = scoreService; } @Override public void run() { System.out.println("---------scoreService updateScore start---------"); this.scoreService.updateScore(1); System.out.println("---------scoreService updateScore end---------"); } }
scoreServiceImplmybatis
@Override @Transactional public void updateScore(int id) { scoreDao.updateScore(id); // try{ int i = 1 / 0; //exception测试注释 i = 1; // } catch (Exception e){ // e.printStackTrace(); // } }
1:userServiceImpl和scoreServiceImpl都打开事务mvc
日志输出:app
---------spring mvc update--------- [DEBUG] 2018-05-23 20:44:38,367 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:243) Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' [DEBUG] 2018-05-23 20:44:38,370 method:org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:107) Adding transactional method 'UserServiceImpl.update2' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' [DEBUG] 2018-05-23 20:44:38,374 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:243) Returning cached instance of singleton bean 'transactionManager' [DEBUG] 2018-05-23 20:44:38,383 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:366) Creating new transaction with name [com.paic.ssm.user.service.impl.UserServiceImpl.update2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' [DEBUG] 2018-05-23 20:44:38,384 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204) Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@139b811] for JDBC transaction [DEBUG] 2018-05-23 20:44:38,391 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:221) Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@139b811] to manual commit ---------UserServiceImpl updateAge start--------- 20:44:38.401 [http-bio-8080-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 20:44:38.408 [http-bio-8080-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@195fbac] 20:44:38.458 [http-bio-8080-exec-9] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@139b811] will be managed by Spring 20:44:38.461 [http-bio-8080-exec-9] DEBUG c.p.ssm.user.dao.IUserDao.updateAge - ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@139b811] 20:44:38.467 [http-bio-8080-exec-9] DEBUG c.p.ssm.user.dao.IUserDao.updateAge - ==> Preparing: update user_t set age = ? 20:44:38.644 [http-bio-8080-exec-9] DEBUG c.p.ssm.user.dao.IUserDao.updateAge - ==> Parameters: 111(Integer) [DEBUG] 2018-05-23 20:44:38,650 method:com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:123) {conn-10010, pstmt-20000} enter cache 20:44:38.650 [http-bio-8080-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@195fbac] ---------UserServiceImpl updateAge end--------- ---------UserServiceImpl method over--------- ---------scoreService updateScore start--------- [DEBUG] 2018-05-23 20:44:38,652 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:753) Initiating transaction commit [DEBUG] 2018-05-23 20:44:38,653 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:243) Returning cached instance of singleton bean 'transactionManager' [DEBUG] 2018-05-23 20:44:38,653 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:267) Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@139b811] [DEBUG] 2018-05-23 20:44:38,653 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:366) Creating new transaction with name [com.paic.ssm.user.service.impl.ScoreServiceImpl.updateScore]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' [DEBUG] 2018-05-23 20:44:38,654 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204) Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1876493] for JDBC transaction [DEBUG] 2018-05-23 20:44:38,654 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:221) Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1876493] to manual commit 20:44:38.655 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 20:44:38.655 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b63214] 20:44:38.655 [Thread-2] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1876493] will be managed by Spring 20:44:38.655 [Thread-2] DEBUG c.p.s.user.dao.IScoreDao.updateScore - ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1876493] 20:44:38.655 [Thread-2] DEBUG c.p.s.user.dao.IScoreDao.updateScore - ==> Preparing: update score_t set score = ? 20:44:38.655 [Thread-2] DEBUG c.p.s.user.dao.IScoreDao.updateScore - ==> Parameters: 1(Integer) [DEBUG] 2018-05-23 20:44:38,656 method:com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:123) {conn-10009, pstmt-20001} enter cache 20:44:38.656 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b63214] [DEBUG] 2018-05-23 20:44:38,656 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:753) Initiating transaction commit [DEBUG] 2018-05-23 20:44:38,656 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:267) Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1876493] 20:44:38.732 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b63214] 20:44:38.732 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b63214] [DEBUG] 2018-05-23 20:44:38,734 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager.java:325) Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1876493] after transaction [DEBUG] 2018-05-23 20:44:38,734 method:org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:327) Returning JDBC Connection to DataSource ---------scoreService updateScore end--------- 20:44:38.819 [http-bio-8080-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@195fbac] 20:44:38.819 [http-bio-8080-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@195fbac] [DEBUG] 2018-05-23 20:44:38,820 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager.java:325) Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@139b811] after transaction [DEBUG] 2018-05-23 20:44:38,821 method:org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:327) Returning JDBC Connection to DataSource ---------spring mvc all---------
能够看到,两个方法均新建了新的事务,说明二者并非共享同一事务ide
2:userServiceImpl打开事务,scoreServiceImpl关闭事务测试
通过试验,发现userServiceImpl开启了新的事务,而scoreServiceImpl并未开启事务。。。ui
继续测试回滚
仅打开scoreServiceImpl的异常测试代码,而且不捕获异常,输出以下:
eb.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:921) Last-Modified value for [/tx-spread/login/test2.do] is: -1 ---------spring mvc update--------- [DEBUG] 2018-05-23 20:58:39,560 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:243) Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' [DEBUG] 2018-05-23 20:58:39,566 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:243) Returning cached instance of singleton bean 'transactionManager' [DEBUG] 2018-05-23 20:58:39,572 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:366) Creating new transaction with name [com.paic.ssm.user.service.impl.UserServiceImpl.update2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' [DEBUG] 2018-05-23 20:58:39,573 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204) Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@150d517] for JDBC transaction [DEBUG] 2018-05-23 20:58:39,578 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:221) Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@150d517] to manual commit ---------UserServiceImpl updateAge start--------- 20:58:39.584 [http-bio-8080-exec-6] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 20:58:39.589 [http-bio-8080-exec-6] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@15f4f4d] 20:58:39.633 [http-bio-8080-exec-6] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@150d517] will be managed by Spring 20:58:39.635 [http-bio-8080-exec-6] DEBUG c.p.ssm.user.dao.IUserDao.updateAge - ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@150d517] 20:58:39.639 [http-bio-8080-exec-6] DEBUG c.p.ssm.user.dao.IUserDao.updateAge - ==> Preparing: update user_t set age = ? 20:58:39.774 [http-bio-8080-exec-6] DEBUG c.p.ssm.user.dao.IUserDao.updateAge - ==> Parameters: 111(Integer) [DEBUG] 2018-05-23 20:58:39,778 method:com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:123) {conn-10010, pstmt-20000} enter cache 20:58:39.779 [http-bio-8080-exec-6] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@15f4f4d] ---------UserServiceImpl updateAge end--------- ---------UserServiceImpl method over--------- ---------scoreService updateScore start--------- [DEBUG] 2018-05-23 20:58:39,781 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:753) Initiating transaction commit [DEBUG] 2018-05-23 20:58:39,782 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:267) Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@150d517] [DEBUG] 2018-05-23 20:58:39,782 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:243) Returning cached instance of singleton bean 'transactionManager' [DEBUG] 2018-05-23 20:58:39,784 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:366) Creating new transaction with name [com.paic.ssm.user.service.impl.ScoreServiceImpl.updateScore]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' [DEBUG] 2018-05-23 20:58:39,784 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204) Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@190f65c] for JDBC transaction [DEBUG] 2018-05-23 20:58:39,784 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:221) Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@190f65c] to manual commit 20:58:39.785 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 20:58:39.785 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@cc6826] 20:58:39.785 [Thread-2] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@190f65c] will be managed by Spring 20:58:39.785 [Thread-2] DEBUG c.p.s.user.dao.IScoreDao.updateScore - ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@190f65c] 20:58:39.785 [Thread-2] DEBUG c.p.s.user.dao.IScoreDao.updateScore - ==> Preparing: update score_t set score = ? 20:58:39.786 [Thread-2] DEBUG c.p.s.user.dao.IScoreDao.updateScore - ==> Parameters: 1(Integer) [DEBUG] 2018-05-23 20:58:39,787 method:com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:123) {conn-10009, pstmt-20001} enter cache 20:58:39.788 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@cc6826] [DEBUG] 2018-05-23 20:58:39,788 method:org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:844) Initiating transaction rollback [DEBUG] 2018-05-23 20:58:39,788 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doRollback(DataSourceTransactionManager.java:282) Rolling back JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@190f65c] 20:58:39.839 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@cc6826] 20:58:39.839 [Thread-2] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@cc6826] [DEBUG] 2018-05-23 20:58:39,840 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager.java:325) Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@190f65c] after transaction [DEBUG] 2018-05-23 20:58:39,840 method:org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:327) Returning JDBC Connection to DataSource Exception in thread "Thread-2" java.lang.ArithmeticException: / by zero at com.paic.ssm.user.service.impl.ScoreServiceImpl.updateScore(ScoreServiceImpl.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at com.sun.proxy.$Proxy17.updateScore(Unknown Source) at com.paic.ssm.user.service.impl.MyThread.run(UserServiceImpl.java:103) 20:58:39.933 [http-bio-8080-exec-6] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@15f4f4d] 20:58:39.933 [http-bio-8080-exec-6] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@15f4f4d] [DEBUG] 2018-05-23 20:58:39,934 method:org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager.java:325) Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@150d517] after transaction [DEBUG] 2018-05-23 20:58:39,935 method:org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:327) Returning JDBC Connection to DataSource ---------spring mvc all---------
userServiceImpl事务提交了,scoreServiceImpl回滚了(日志抛出挺长的),和DB结果一致,因为两个方法位于不一样的事务中,也很符合预期
当scoreServiceImpl关闭事务,发现userServiceImpl事务回滚,而是scoreServiceImpl并未回滚,也符合预期
因为两个service位于不一样的事务,因此提交和回滚均是按照自身的事务规则。
从实验能够看出,若是在事务处理的方法中开启了子线程,事务是不会传播的,子线程的事务由其自己调用的方法的事务决定的,若是子线程调用的方法无事务,那么其就以无事务方式运行