关于spring 事物传播性的研究

spring的一大特色就是数据库事务管理方便,我们在代码中编写代码时,看不到事务的使用,关键是spring 使用了AOP进行事务拦截。

 

这篇文章主要介绍spring的事务传播性。

 

1.为什么要介绍这个:

介绍一下使用场景:

在系统中我们使用了一个流水号,这个功能实现如下:

1.先使用for update 进行行锁。

select * from sys_identity t where alias=‘REQUESTID‘ for update;

这个时候锁是不会释放的。

2.使用更新语句更新这个流水号。

UPDATE sys_identity SET
        name=#{name,jdbcType=VARCHAR} ,
        alias=#{alias,jdbcType=VARCHAR} ,
        REGULATION=#{rule,jdbcType=VARCHAR} ,
        genType=#{genType,jdbcType=NUMERIC} ,
        noLength=#{noLength,jdbcType=NUMERIC} ,
        initValue=#{initValue,jdbcType=NUMERIC} ,
        curValue=#{curValue,jdbcType=NUMERIC} ,
        step=#{step,jdbcType=NUMERIC} ,
        curDate=#{curDate,jdbcType=VARCHAR}
        WHERE
        id=#{id}

执行完成后,就会释放之前的锁定。

 

这个功能在单独调用的时候,是没有问题的,但是如果这个获取流水号的方法,放到一个长的事务中,势必这个就成了瓶颈。

应为长事务方法会一直锁住这个,不会提交。

 

2.解决方案:

如果我们在长事务方法中,能够将这个获取流水号的方法新起一个事务,这样这个方法很快就会提交。这个时候我们就可以利用事务的传播

性来解决这个问题。

 

下面介绍一下事务传播性概念:

PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启
PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,

      则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

在默认的情况下,我们采用的是

PROPAGATION_REQUIRED

举例如下:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
              <tx:method name="get*" read-only="true"/>
            <tx:method name="is*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" isolation="DEFAULT"/>
        </tx:attributes>
</tx:advice>

这种情况下,只要被拦截的业务方法抛出异常都会回滚。

 

如果我想实现上面的需求,我们修改配置如下:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="nextId" propagation="REQUIRES_NEW" />
              <tx:method name="get*" read-only="true"/>
            <tx:method name="is*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" isolation="DEFAULT"/>
        </tx:attributes>
</tx:advice>

这里我加入了一个方法进行单独配置:

方法名为nextId ,这里我们配置了REQUIRES_NEW。

预期的目标是,让这个方法产生新的事务。

 

3.测试代码如下

@Service
public class ServiceExample {

    @Resource
    WorkPlandetailDao workPlandetailDao;
    @Resource
    IdentityService identityService;

    public void updWork(){
        WorkPlandetail plandetail=new WorkPlandetail();
        plandetail.setId(UniqueIdUtil.genId());
        plandetail.setDocids(1L);
        plandetail.setRq(new Date());
        plandetail.setUserid(1L);

        workPlandetailDao.add(plandetail);

        identityService.nextId("REQUESTID");
        boolean rtn=true;
        if(rtn){
            throw new RuntimeException("抛出异常");
        }
    }
}

这个代码如果成立结果应该是这样

1.第一个添加应该回滚。

2.流水号产生不回滚。

 

4.详细日志如下:

事务启动

[BPM] 2015-01-22 14:37:27 DEBUG [main] AnnotationTransactionAttributeSource.getTransactionAttribute(106) | Adding transactional method ‘transTest‘ with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ‘‘

[BPM] 2015-01-22 14:37:27 DEBUG [main] DataSourceTransactionManager.getTransaction(365) | Creating new transaction with name [transTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ‘‘

[BPM] 2015-01-22 14:37:27 DEBUG [main] DataSourceTransactionManager.doBegin(204) | Acquired Connection [1940809161([email protected])] for JDBC transaction

[BPM] 2015-01-22 14:37:27 DEBUG [main] DataSourceTransactionManager.doBegin(221) | Switching JDBC Connection [1940809161([email protected])] to manual commit

[BPM] 2015-01-22 14:37:49 DEBUG [main] DataSourceTransactionManager.handleExistingTransaction(470) | Participating in existing transaction

[BPM] 2015-01-22 14:37:52 DEBUG [main] JdbcTemplate.query(634) | Executing prepared SQL query

[BPM] 2015-01-22 14:37:52 DEBUG [main] JdbcTemplate.execute(569) | Executing prepared SQL statement [SELECT bound,incremental FROM SYS_DB_ID T WHERE T.ID=?]

[BPM] 2015-01-22 14:37:52 DEBUG [main] DataSourceUtils.doGetConnection(110) | Fetching JDBC Connection from DataSource

[BPM] 2015-01-22 14:37:53 DEBUG [main] DataSourceUtils.doGetConnection(114) | Registering transaction synchronization for JDBC Connection

[BPM] 2015-01-22 14:37:53 DEBUG [main] JdbcTemplate.update(810) | Executing prepared SQL update

[BPM] 2015-01-22 14:37:53 DEBUG [main] JdbcTemplate.execute(569) | Executing prepared SQL statement [UPDATE SYS_DB_ID  SET BOUND=? WHERE ID=?]

[BPM] 2015-01-22 14:37:53 DEBUG [main] JdbcTemplate.doInPreparedStatement(819) | SQL update affected 1 rows

[BPM] 2015-01-22 14:37:54 DEBUG [main] Connection.debug(28) | ooo Connection Opened

[BPM] 2015-01-22 14:37:54 DEBUG [main] PreparedStatement.debug(28) | ==>  Executing: INSERT INTO WORKPLANDETAIL (ID,WORKID,USERID,DOCIDS,RQ,TIME) VALUES (?, ?, ?, ?, ?, ?)

[BPM] 2015-01-22 14:37:54 DEBUG [main] PreparedStatement.debug(28) | ==> Parameters: 10000027280000(Long), null, 1(Long), 1(Long), 2015-01-22(Date), null

[BPM] 2015-01-22 14:37:54 DEBUG [main] Connection.debug(28) | xxx Connection Closed

挂起当前事务,新起一个事务。

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.handleExistingTransaction(415) | Suspending current transaction, creating new transaction with name [com.hotent.platform.service.system.IdentityService.nextId]

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceUtils.doReleaseConnection(332) | Returning JDBC Connection to DataSource

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.doBegin(204) | Acquired Connection [1210980916([email protected])] for JDBC transaction

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.doBegin(221) | Switching JDBC Connection [1210980916([email protected])] to manual commit

[BPM] 2015-01-22 14:37:58 DEBUG [main] Connection.debug(28) | ooo Connection Opened

[BPM] 2015-01-22 14:37:58 DEBUG [main] PreparedStatement.debug(28) | ==>  Executing: SELECT id,name,alias,REGULATION,genType,noLength,initValue,curValue,step,curDate FROM SYS_IDENTITY WHERE alias=? FOR UPDATE

[BPM] 2015-01-22 14:37:58 DEBUG [main] PreparedStatement.debug(28) | ==> Parameters: REQUESTID(String)

[BPM] 2015-01-22 14:37:58 DEBUG [main] Connection.debug(28) | xxx Connection Closed

[BPM] 2015-01-22 14:37:58 DEBUG [main] Connection.debug(28) | ooo Connection Opened

[BPM] 2015-01-22 14:37:58 DEBUG [main] PreparedStatement.debug(28) | ==>  Executing: UPDATE sys_identity SET name=? , alias=? , REGULATION=? , genType=? , noLength=? , initValue=? , curValue=? , step=? , curDate=? WHERE id=?

[BPM] 2015-01-22 14:37:58 DEBUG [main] PreparedStatement.debug(28) | ==> Parameters: 工号(String), REQUESTID(String), {NO}(String), 0(Short), 1(Integer), 60000(Integer), 90191(Integer), 1(Short), 2013520(String), 10000006120000(Long)

[BPM] 2015-01-22 14:37:58 DEBUG [main] Connection.debug(28) | xxx Connection Closed

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.processCommit(752) | Initiating transaction commit

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.doCommit(264) | Committing JDBC transaction on Connection [1210980916([email protected])]

提交流水号事务

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.doCleanupAfterCompletion(322) | Releasing JDBC Connection [1210980916([email protected])] after transaction

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceUtils.doReleaseConnection(332) | Returning JDBC Connection to DataSource

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.cleanupAfterCompletion(1015) | Resuming suspended transaction after completion of inner transaction

恢复当前事务

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.processRollback(850) | Participating transaction failed - marking existing transaction as rollback-only

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.doSetRollbackOnly(293) | Setting JDBC transaction [1940809161([email protected])] rollback-only

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.commit(711) | Global transaction is marked as rollback-only but transactional code requested commit

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.processRollback(843) | Initiating transaction rollback

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.doRollback(279) | Rolling back JDBC transaction on Connection [1940809161([email protected])]

事务回滚

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.doCleanupAfterCompletion(322) | Releasing JDBC Connection [1940809161([email protected])] after transaction

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceUtils.doReleaseConnection(332) | Returning JDBC Connection to DataSource

[BPM] 2015-01-22 14:38:16 DEBUG [ShutdownHook] ShutdownHook.run(93) | Running ShutdownHook

[BPM] 2015-01-22 14:38:16 INFO [Shutdown Hook] dbpool.shutdown(484) | Shutting down ‘dbpool‘ pool immediately [Shutdown Hook]

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.stop(163) | Server is stopping.

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServletDestination.setMessageObserver(56) | unregistering incoming observer: [email protected]

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.destroy(185) | unregister the server to serverRegistry

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.stop(163) | Server is stopping.

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServletDestination.setMessageObserver(56) | unregistering incoming observer: [email protected]

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.destroy(185) | unregister the server to serverRegistry

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.stop(163) | Server is stopping.

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServletDestination.setMessageObserver(56) | unregistering incoming observer: [email protected]

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.destroy(185) | unregister the server to serverRegistry

[BPM] 2015-01-22 14:38:16 DEBUG [Shutdown Hook] dbpool.removeProxyConnection(441) | 000006 (00/02/00) - #0003 removed because of shutdown.

[BPM] 2015-01-22 14:38:16 DEBUG [Shutdown Hook] dbpool.shutdown(547) | Connection #3 closed

[BPM] 2015-01-22 14:38:16 DEBUG [Shutdown Hook] dbpool.removeProxyConnection(441) | 000006 (00/01/00) - #0001 removed because of shutdown.

[BPM] 2015-01-22 14:38:16 DEBUG [Shutdown Hook] dbpool.shutdown(547) | Connection #1 closed

[BPM] 2015-01-22 14:38:16 DEBUG [Shutdown Hook] dbpool.removeProxyConnection(441) | 000006 (00/00/00) - #0002 removed because of shutdown.

[BPM] 2015-01-22 14:38:16 DEBUG [Shutdown Hook] dbpool.shutdown(547) | Connection #2 closed

[BPM] 2015-01-22 14:38:16 INFO [Shutdown Hook] dbpool.shutdown(564) | ‘dbpool‘ pool has been closed down by Shutdown Hook in 30 milliseconds.

[BPM] 2015-01-22 14:38:16 INFO [Shutdown Hook] PrototyperController.shutdown(100) | Stopping Prototyper thread

[BPM] 2015-01-22 14:38:16 INFO [Shutdown Hook] HouseKeeperController.shutdown(107) | Stopping HouseKeeper thread

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.destroy(185) | unregister the server to serverRegistry

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.destroy(185) | unregister the server to serverRegistry

[BPM] 2015-01-22 14:38:16 DEBUG [Thread-20] ServerImpl.destroy(185) | unregister the server to serverRegistry

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.getTransaction(365) | Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] HouseKeeperController.register(84) | Registering ‘dbpool‘ house keeper

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] HouseKeeperController.register(92) | Starting a house keeper thread

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] dbpool.initialise(168) | Remembering default value: getTransactionIsolation() = 2

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] dbpool.initialise(168) | Remembering default value: getHoldability() = 1

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] dbpool.initialise(168) | Remembering default value: getCatalog() = null

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] dbpool.initialise(168) | Remembering default value: isReadOnly() = false

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] dbpool.initialise(168) | Remembering default value: getTypeMap() = {}

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] dbpool.buildConnection(204) | 000000 (01/01/00) - Connection #1 created on demand = ACTIVE

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.doBegin(204) | Acquired Connection [741406706([email protected])] for JDBC transaction

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.doBegin(221) | Switching JDBC Connection [741406706([email protected])] to manual commit

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] Connection.debug(28) | ooo Connection Opened

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] Connection.debug(28) | xxx Connection Closed

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.processCommit(752) | Initiating transaction commit

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.doCommit(264) | Committing JDBC transaction on Connection [741406706([email protected])]

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.doCleanupAfterCompletion(322) | Releasing JDBC Connection [741406706([email protected])] after transaction

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceUtils.doReleaseConnection(332) | Returning JDBC Connection to DataSource

[BPM] 2015-01-22 14:38:17 DEBUG [Prototyper] dbpool.buildConnection(204) | 000001 (00/02/00) - Connection #2 created to achieve minimum of 3 = AVAILABLE

[BPM] 2015-01-22 14:38:17 DEBUG [Prototyper] dbpool.buildConnection(204) | 000001 (00/03/00) - Connection #3 created to achieve minimum of 3 = AVAILABLE

时间: 2024-08-12 21:56:02

关于spring 事物传播性的研究的相关文章

spring事务传播性理解

什么是spring的事务传播性 个人的理解, 首先先说一下事务传播性,事务传播性就是,事务中还包括另外的事务,事务之间是怎么相互影响,然后如何执行的,这就是事务传播性 spring事务传播性就是spring中是如何去规定事务是如何执行的,情况如下: public class DemoServiceA { //事务A @Transactional(propagation=Propagation.REQUIRED)//对于外层事务来说(相对的,如果demoMthodA加到demoMthodC中,de

spring事物传播propagation各类别含义

在spring事务中针对注解transaction,我们在定义的时候会注明事物的传播类别,默认的是required. required:使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法必须运行在一个事务,如果当前存在事务,则加入这个事务,成为一个整体. ex:领导没饭吃,我有钱,我自己买了自己吃:领导有饭吃,会分给我一起吃. supports:如果当前有事务,则使用事务:如果当前没有事务,则不使用事务. ex:领导没饭吃,我也没饭吃:领导有饭吃,我也有饭吃. mandatory:该传

spring事物传播机制与隔离级别

转载自:http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html7个传播行为,4个隔离级别, Spring事务的传播行为和隔离级别[transaction behavior and isolated level]2007-08-01 16:33事务的传播行为和隔离级别[transaction behavior and isolated level] Spring中事务的定义:一.Propagation : key属性确定

spring事务传播性与隔离级别

事务的7种传播级别: 1)PROPAGATION_REQUIRED:支持当前事务,没有事务就新建一个. 2)PROPAGATION_SUPPORTS:支持当前事务,如果没有事务,以非事务方式处理 3)PROPAGATION_MANDATORY:支持当前事务,没有事务就抛异常 4)PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起 5)PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,有事务则挂起 6)PROPAGATION_NEV

spring事物传播属性

PROPAGATION_REQUIRED Support a current transaction; create a new one if none exists. 支持一个当前事务;如果不存在,创建一个新的. This is typically the default setting of a transaction definition, and typically defines a transaction synchronization scope. 默认设置,后面的不懂 PROPA

理解 spring 事务传播行为与数据隔离级别

事务,是为了保障逻辑处理的原子性.一致性.隔离性.永久性. 通过事务控制,可以避免因为逻辑处理失败而导致产生脏数据等等一系列的问题. 事务有两个重要特性: 事务的传播行为 数据隔离级别 1.事务传播行为(Transaction Behavior) 传播行为级别,定义的是事务的控制范围.通俗点说,执行到某段代码时,对已存在事务的不同处理方式. Spring 对 JDBC 的事务隔离级别进行了补充和扩展,并提出了 7 种事务传播行为. 1)Spring 中提供的 7 种传播行为 PROPAGATIO

spring 中常用的两种事务配置方式以及事务的传播性、隔离级别

转载:http://blog.csdn.net/qh_java/article/details/51811533 一.注解式事务 1.注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo. 2.事务配置实例 (1).spring+mybatis 事务配置 [html] view plain copy <!-- 定义事务管理器 --> <bean id="transactionManager" class="

spring事物的七种事物传播属性行为及五种隔离级别

首先,说说什么事务(Transaction). 事务,就是一组操作数据库的动作集合.事务是现代数据库理论中的核心概念之一.如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务.当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交.由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态. 其中spring七个事物传播属性: PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. PR

Spring事务的5种隔离级别和7种传播性

隔离级别 isolation,5 种: ISOLATION_DEFAULT,ISOLATION_READ_UNCOMMITTED,ISOLATION_READ_COMMITTED,ISOLATION_REPEATABLE_READ,ISOLATION_SERIALIZABLE, 隔离级别解决的问题: 脏读, 幻读, 不可重复读, 传播性 propagation,7 种: PROPAGATION_REQUIRED,PROPAGATION_SUPPORTS,PROPAGATION_MANDATORY