关于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(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 事物传播性的研究的更多相关文章
- Spring 事物传播特性
Spring 事物传播特性 这是Spring官方的定义 一共有7种 摘自源码省略了一部分 public interface TransactionDefinition { int PROPAGATIO ...
- Spring事物传播行为
Spring事物传播行为 Spring中事务的定义: Propagation(key属性确定代理应该给哪个方法增加事务行为.这样的属性最重要的部份是传播行为.)有以下选项可供使用: PROPAGATI ...
- spring 事务传播性
一.什么是事务传播性 大白话讲就是,方法之间互相调用的时候,事务如何传播,比如A()调用B(),B()的事务是和A()共用一个事务(失败一起提交)? 还是新事务(两者事务互不影响)?,还是说B()不需 ...
- Spring事务传播性
事务是逻辑处理原子性的保证手段,通过使用事务控制,可以极大的避免出现逻辑处理失败导致的脏数据等问题.事务最重要的两个特性,是事务的传播级别和数据隔离级别.传播级别定义的是事务的控制范围,事务隔离级别定 ...
- spring事物传播机制与隔离级别
转载自:http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html7个传播行为,4个隔离级别, Spring事务的传播行为和隔 ...
- spring事物传播机制 事物隔离级别
Spring事务类型详解: PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. PROPAGATION_SUPPORTS--支持当前事务,如 ...
- spring事务传播性与隔离级别
事务的7种传播级别: 1)PROPAGATION_REQUIRED:支持当前事务,没有事务就新建一个. 2)PROPAGATION_SUPPORTS:支持当前事务,如果没有事务,以非事务方式处理 3) ...
- spring事物传播属性
PROPAGATION_REQUIRED Support a current transaction; create a new one if none exists. 支持一个当前事务;如果不存在 ...
- 事务传播性、隔离性与MVCC
一.事务传播性 1.1 什么是事务的传播性 事务的传播性一般在事务嵌套时候使用,比如在事务A里面调用了另外一个使用事务的方法,那么这俩个事务是各自作为独立的事务执行提交,还是内层的事务合并到外层的事务 ...
随机推荐
- ubuntu下安装gradle
1.下载gradle 下载地址:当前版本gradle-2.10-all.zip http://gradle.org/gradle-download/ 2.解压安装gradle unzip gradle ...
- idea编辑器HttpServlet httpServlet = ServletActionContext.getServletContext().getRealPath();方法无法使用
HttpServlet httpServlet = ServletActionContext.getServletContext().getRealPath(); 前几天在使用idea的时候发现这个方 ...
- LTE Module User Documentation(翻译5)——Mobility Model with Buildings
LTE用户文档 (如有不当的地方,欢迎指正!) 8 Mobility Model with Buildings 我们现在通过例子解释如何在 ns-3 仿真程序中使用 buildings 模型(特别 ...
- ACCESS 数据库使用配置调整解决方案
分享到 一键分享 QQ空间 新浪微博 百度搜藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 64位服务器无法使用ac ...
- Linux Shell Bash 带有特殊含义的退出码
linux在执行完一条命令后,使用 echo $? 会显示上一条命令是否执行成功,相关状态码如下 0为成功 表格 D-1. "保留的"退出码 退出码的值 含义 例子 注释 1 通用 ...
- mysql 1030 Got error 28 from storage engine
mysql 1030 Got error 28 from storage engine 错误原因:磁盘临时空间不够. 解决办法:df -h 查看设备存储的使用情况 du -h --max-depth= ...
- 代码中特殊的注释技术——TODO、FIXME和XXX的用处
本文内容概要: 代码中特殊的注释技术--TODO.FIXME和XXX的用处. 前言:今天在阅读Qt Creator的源代码时,发现一些注释中有FIXME英文单词,用英文词典居然查不到其意义!实际上, ...
- html5实现GIF动画!
代码如下: <!DOCTYPE html><html> <head> <meta charset="utf-8"&g ...
- Object Pascal 语言基础
Delphi 是以Object Pascal 语言为基础的可视化开发工具,所以要学好Delphi,首先要掌握的就是Object Pascal 语言.Object Pascal语言是Pascal之父在1 ...
- 基础2 JVM
1. 内存模型以及分区,需要详细到每个区放什么. //运行时数据区域 方法区 Method Area 各个线程共享的内存区域 存储已被虚拟机加载的类信息 常量 静态变量 即时编译器编译后的代码 虚拟机 ...