spring事务传播特性实验(2):PROPAGATION_REQUIRED实验结果与分析

  本文延续上一文章(spring事务传播特性实验(1):数据准备),在已经准备好环境的情况下,做如下的实验,以验证spring传播特性,加深对spring传播特性的理解。

  本次主要验证PROPAGATION_REQUIRED的传播特性: 

  TransactionDefinition.PROPAGATION_REQUIRED

  TransactionDefinition.PROPAGATION_REQUIRED:根据spring的定义PROPAGATION_REQUIRED即需要事务的支持,如果没有的情况下会自己创建一个新的事务

  我们进行如下测试:

  A、外部有事务的情况下:http://localhost:8080/test1?type=0

DEBUG  137  DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465] for JDBC transaction
DEBUG  143  DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465] to manual commit
 INFO  149  INFO  com.sapling.project.module.biz.TransactionTest - [outerTransaction]current transaction name : outerTransaction
 INFO  151  INFO  com.sapling.project.module.biz.TransactionTest - {name:0}
DEBUG  263  DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Participating in existing transaction
 INFO  263  INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction 0 ]current transaction name : outerTransaction
 INFO  263  INFO  com.sapling.project.module.biz.TransactionTest - {name:0}
 INFO  267  INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction]current transaction outerTransaction commit.
DEBUG  268  DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
DEBUG  268  DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465]
DEBUG  274  DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465] after transaction
DEBUG  274  DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
 INFO  275  INFO  com.sapling.project.module.biz.TransactionTest - [outerTransaction]current transaction null commit.

  从日志中我们可以看到这样的记录:Participating in existing transaction,加入到一个已经存在的事务中。

  数据表插入成功

+----+----------+------+--------+
| id | name     | sex  | status |
+----+----------+------+--------+
|  8 | 0-true   | NULL |   NULL |
|  9 | i-0-true | NULL |   NULL |

  B、外部没有事务的情况下:http://localhost:8080/test3?type=0

 INFO 093 INFO  com.sapling.project.module.biz.TransactionTest - [outerTransaction] did not have transaction 
 INFO 094 INFO  com.sapling.project.module.biz.TransactionTest - {name:0}
DEBUG 094 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
DEBUG 104 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
DEBUG 104 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG 104 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465] for JDBC transaction
DEBUG 104 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465] to manual commit
 INFO 106 INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction 0 ]current transaction name : null
 INFO 107 INFO  com.sapling.project.module.biz.TransactionTest - {name:0}
DEBUG 111 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
DEBUG 111 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465]
DEBUG 118 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1512c465] after transaction
DEBUG 119 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
 INFO 119 INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction]current transaction null commit.

   Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,创建一个新的事务,传播特性为PROPAGATION_REQUIRED,隔离级别为默认。

  数据表插入成功

mysql> select * from sys_user
    -> ;
+----+----------+------+--------+
| id | name     | sex  | status |
+----+----------+------+--------+
|  8 | 0-true   | NULL |   NULL |
|  9 | i-0-true | NULL |   NULL |
| 10 | o-0-true | NULL |   NULL |
| 11 | i-0-true | NULL |   NULL |
+----+----------+------+--------+
4 rows in set (0.00 sec)

  C、外部有事务,但内部异常的情况下:

  系统报500错误,日志如下:

165 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
172 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5d7163af] for JDBC transaction
172 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5d7163af] to manual commit
174 INFO  com.sapling.project.module.biz.TransactionTest - [outerTransaction]current transaction name : outerTransaction
174 INFO  com.sapling.project.module.biz.TransactionTest - {name:o-0-true}
178 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Participating in existing transaction
178 INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction 0 ]current transaction name : outerTransaction
178 INFO  com.sapling.project.module.biz.TransactionTest - {name:11111111111111111111111111111}
284 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Participating transaction failed - marking existing transaction as rollback-only
284 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Setting JDBC transaction [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5d7163af] rollback-only
284 INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction ]current transaction outerTransaction rollback. 284 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Global transaction is marked as rollback-only but transactional code requested commit 284 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback 284 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5d7163af] 319 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5d7163af] after transaction 319 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource 326 DEBUG org.springframework.web.servlet.DispatcherServlet - Could not complete request org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction

  可以看到,事务在在内部方法中就直接回滚了,整个事务已经完成了,外部事务再在做回滚操作的时候,就报错了,这里可以在回滚操作之前加上!status.isCompleted()检查事务是不是完成了,完成了则不需要再回滚了。

  检查数据库,可以看出事务整个失败了,不管是内部方法还是外部方法的数据都没有插入成功:

mysql> select * from sys_user;
+----+----------+------+--------+
| id | name     | sex  | status |
+----+----------+------+--------+
|  8 | 0-true   | NULL |   NULL |
|  9 | i-0-true | NULL |   NULL |
| 10 | o-0-true | NULL |   NULL |
| 11 | i-0-true | NULL |   NULL |
+----+----------+------+--------+
4 rows in set (0.00 sec)

  D、外部没有事务,内部执行失败:

.964 INFO  com.sapling.project.module.biz.TransactionTest - [outerTransaction] did not have transaction 
.964 INFO  com.sapling.project.module.biz.TransactionTest - {name:0-true}
.964 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
.973 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
.973 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
.973 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5b773cec] for JDBC transaction
.973 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5b773cec] to manual commit
.974 INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction 0 ]current transaction name : null
.974 INFO  com.sapling.project.module.biz.TransactionTest - {name:11111111111111111111111111111}
.978 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback
.978 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5b773cec]
.982 DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5b773cec] after transaction
.982 DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
.982 INFO  com.sapling.project.module.biz.TransactionTest - [doInnerTransaction ]current transaction null rollback.

  

  数据库表查询结果:

mysql> select * from sys_user;
+----+----------+------+--------+
| id | name     | sex  | status |
+----+----------+------+--------+
|  8 | 0-true   | NULL |   NULL |
|  9 | i-0-true | NULL |   NULL |
| 10 | o-0-true | NULL |   NULL |
| 11 | i-0-true | NULL |   NULL |
| 16 | 0-true   | NULL |   NULL |
+----+----------+------+--------+
5 rows in set (0.00 sec)

  可以看出来,内部事务的失败不同事务下的插入操作。

由如上的几个执行结果可以看出来,Required传播模式下的事务,会在已经存在事务的情况下加入已有的事务,按照现有事务的流程执行,没有事务的情况下,新建一个事务执行,其执行的结果对其他的事务不产生影响。

原文地址:https://www.cnblogs.com/lyzw/p/9000564.html