Spring事务传播实验剖析(二)

第一节讲述了不同service之间事务的传播,经过小实验,还原了spring的事务传播结论,这期实验下service中开启新线程后,事务如何传播

首先是controller发起请求:

@RequestMapping(value="/test2")
public void insert2() {
	System.out.println("---------spring mvc update---------");
	userService.update2(111,"aaaazz");
	System.out.println("---------spring mvc all---------");
}
	

userServiceImpl


@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---------");
		
}

涉及的内部类:


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---------");
	}
}

scoreServiceImpl

	@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都打开事务

日志输出:


  ---------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---------

可以看到,两个方法均新建了新的事务,说明两者并不是共享同一事务

2:userServiceImpl打开事务,scoreServiceImpl关闭事务

经过试验,发现userServiceImpl开启了新的事务,而scoreServiceImpl并未开启事务。。。

继续测试回滚

仅打开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位于不同的事务,所以提交和回滚均是按照自身的事务规则。

从实验可以看出,如果在事务处理的方法中开启了子线程,事务是不会传播的,子线程的事务由其本身调用的方法的事务决定的,如果子线程调用的方法无事务,那么其就以无事务方式运行

 

转载于:https://my.oschina.net/u/1474131/blog/1816207

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值