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(oracle.jdbc.driver.T4CConnection@c65d26e)] for JDBC transaction

[BPM] 2015-01-22 14:37:27 DEBUG [main] DataSourceTransactionManager.doBegin(221) | Switching JDBC Connection [1940809161(oracle.jdbc.driver.T4CConnection@c65d26e)] 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(oracle.jdbc.driver.T4CConnection@1a78b825)] for JDBC transaction

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.doBegin(221) | Switching JDBC Connection [1210980916(oracle.jdbc.driver.T4CConnection@1a78b825)] 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(oracle.jdbc.driver.T4CConnection@1a78b825)]

提交流水号事务

[BPM] 2015-01-22 14:37:58 DEBUG [main] DataSourceTransactionManager.doCleanupAfterCompletion(322) | Releasing JDBC Connection [1210980916(oracle.jdbc.driver.T4CConnection@1a78b825)] 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(oracle.jdbc.driver.T4CConnection@c65d26e)] 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(oracle.jdbc.driver.T4CConnection@c65d26e)]

事务回滚

[BPM] 2015-01-22 14:38:16 DEBUG [main] DataSourceTransactionManager.doCleanupAfterCompletion(322) | Releasing JDBC Connection [1940809161(oracle.jdbc.driver.T4CConnection@c65d26e)] 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: org.apache.cxf.transport.ChainInitiationObserver@2d4e7451

[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: org.apache.cxf.transport.ChainInitiationObserver@2ad22562

[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: org.apache.cxf.transport.ChainInitiationObserver@5c894b4f

[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(oracle.jdbc.driver.T4CConnection@63cffc5f)] for JDBC transaction

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.doBegin(221) | Switching JDBC Connection [741406706(oracle.jdbc.driver.T4CConnection@63cffc5f)] 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(oracle.jdbc.driver.T4CConnection@63cffc5f)]

[BPM] 2015-01-22 14:38:17 DEBUG [Thread-20] DataSourceTransactionManager.doCleanupAfterCompletion(322) | Releasing JDBC Connection [741406706(oracle.jdbc.driver.T4CConnection@63cffc5f)] 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

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

  1. Spring 事物传播特性

    Spring 事物传播特性 这是Spring官方的定义 一共有7种 摘自源码省略了一部分 public interface TransactionDefinition { int PROPAGATIO ...

  2. Spring事物传播行为

    Spring事物传播行为 Spring中事务的定义: Propagation(key属性确定代理应该给哪个方法增加事务行为.这样的属性最重要的部份是传播行为.)有以下选项可供使用: PROPAGATI ...

  3. spring 事务传播性

    一.什么是事务传播性 大白话讲就是,方法之间互相调用的时候,事务如何传播,比如A()调用B(),B()的事务是和A()共用一个事务(失败一起提交)? 还是新事务(两者事务互不影响)?,还是说B()不需 ...

  4. Spring事务传播性

    事务是逻辑处理原子性的保证手段,通过使用事务控制,可以极大的避免出现逻辑处理失败导致的脏数据等问题.事务最重要的两个特性,是事务的传播级别和数据隔离级别.传播级别定义的是事务的控制范围,事务隔离级别定 ...

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

    转载自:http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html7个传播行为,4个隔离级别, Spring事务的传播行为和隔 ...

  6. spring事物传播机制 事物隔离级别

    Spring事务类型详解: PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. PROPAGATION_SUPPORTS--支持当前事务,如 ...

  7. spring事务传播性与隔离级别

    事务的7种传播级别: 1)PROPAGATION_REQUIRED:支持当前事务,没有事务就新建一个. 2)PROPAGATION_SUPPORTS:支持当前事务,如果没有事务,以非事务方式处理 3) ...

  8. spring事物传播属性

    PROPAGATION_REQUIRED Support a current transaction; create a new one if none exists.  支持一个当前事务;如果不存在 ...

  9. 事务传播性、隔离性与MVCC

    一.事务传播性 1.1 什么是事务的传播性 事务的传播性一般在事务嵌套时候使用,比如在事务A里面调用了另外一个使用事务的方法,那么这俩个事务是各自作为独立的事务执行提交,还是内层的事务合并到外层的事务 ...

随机推荐

  1. ubuntu下安装gradle

    1.下载gradle 下载地址:当前版本gradle-2.10-all.zip http://gradle.org/gradle-download/ 2.解压安装gradle unzip gradle ...

  2. idea编辑器HttpServlet httpServlet = ServletActionContext.getServletContext().getRealPath();方法无法使用

    HttpServlet httpServlet = ServletActionContext.getServletContext().getRealPath(); 前几天在使用idea的时候发现这个方 ...

  3. LTE Module User Documentation(翻译5)——Mobility Model with Buildings

    LTE用户文档 (如有不当的地方,欢迎指正!) 8 Mobility Model with Buildings   我们现在通过例子解释如何在 ns-3 仿真程序中使用 buildings 模型(特别 ...

  4. ACCESS 数据库使用配置调整解决方案

    分享到 一键分享 QQ空间 新浪微博 百度搜藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 64位服务器无法使用ac ...

  5. Linux Shell Bash 带有特殊含义的退出码

    linux在执行完一条命令后,使用 echo $? 会显示上一条命令是否执行成功,相关状态码如下 0为成功 表格 D-1. "保留的"退出码 退出码的值 含义 例子 注释 1 通用 ...

  6. mysql 1030 Got error 28 from storage engine

    mysql 1030 Got error 28 from storage engine 错误原因:磁盘临时空间不够. 解决办法:df -h 查看设备存储的使用情况 du -h --max-depth= ...

  7. 代码中特殊的注释技术——TODO、FIXME和XXX的用处

    本文内容概要: 代码中特殊的注释技术--TODO.FIXME和XXX的用处. 前言:今天在阅读Qt  Creator的源代码时,发现一些注释中有FIXME英文单词,用英文词典居然查不到其意义!实际上, ...

  8. html5实现GIF动画!

     代码如下: <!DOCTYPE html><html>    <head>        <meta charset="utf-8"&g ...

  9. Object Pascal 语言基础

    Delphi 是以Object Pascal 语言为基础的可视化开发工具,所以要学好Delphi,首先要掌握的就是Object Pascal 语言.Object Pascal语言是Pascal之父在1 ...

  10. 基础2 JVM

    1. 内存模型以及分区,需要详细到每个区放什么. //运行时数据区域 方法区 Method Area 各个线程共享的内存区域 存储已被虚拟机加载的类信息 常量 静态变量 即时编译器编译后的代码 虚拟机 ...