Spring事務傳播實驗剖析(二)

第一節講述了不一樣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位於不一樣的事務,因此提交和回滾均是按照自身的事務規則。

從實驗能夠看出,若是在事務處理的方法中開啓了子線程,事務是不會傳播的,子線程的事務由其自己調用的方法的事務決定的,若是子線程調用的方法無事務,那麼其就以無事務方式運行

相關文章
相關標籤/搜索