Spring3之事务管理
事务管理是企业应用开发中确保数据完整性和一致性的关键技术。对于并发和分布式坏境中从不可预期的错误中恢复来说,事务管理特别重要。Spring作为一个企业应用框架,在不同的事务管理API之上提供了一个抽象层。Spring支持编程式和声明式两种事务管理。编程式事务管理通过在业务方法中嵌入控制事务提交和回滚的事务管理代码来实现,自己定义事务提交和回滚的规则,因此这样代码会很多重复,不能为不同的应用程序启用和禁用事务管理;而声明式事务管理在大部分情况下比编程式事务管理好,它通过声明将事务管理代码从业务方法中分离出来,但其灵活性不如编程式事务管理。spring支持的事务属性包括传播行为、隔离级别、回滚规则、事务超时和事务的只读属性。
事务是一系列作为单独工作单元处理的操作,其有四个关键属性: ACID
原子性:事务是一个包含一系列的原子操作,事务的原子性确保这些操作全部完成或者完全无效。
一致性:一旦事务的所有操作结束,事务就被提交。然后你的数据和资源将处于遵循业务规则的一致状态。
隔离性:因为同时在相同数据集上可能有许多事务处理,每个事务应该与其他事务隔离,避免数据损坏。
持久性:一旦事务完成,它的结果应该能承受任何系统错误。通常,事务的结果被写入持续性存储。
我们可以使用Jdbc API如setAutoCommit,commit,rollback来进行事务管理,Spring的事务支持提供了一组技术独立的机制,包括事务管理器(PlatformTransactionManager)、事务模板(TransactionTemplate)和事务声明支持,以简化事务管理。
Spring的事务抽象包括3个主要接口,即PlatformTransactionManager、TransactionDefinition、TransactionStatus。PlatformTransactionManager负责界定事务边界,TransactionDefinition负责定义事务相关属性,包括隔离级别、传播行为等,前者参照后则的属性定义来开启相关事务,事务开启后到事务结束的事务状态是由TransactionStatus负责,我们也可以通过TransactionStatus对事务进行有限的控制。
1.选择一个事务管理器
Spring的核心事务管理抽象基于PlatformTransactionManager接口,它封装了一组用于事务管理的技术独立方法。其提供了三种处理事务的方法:
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException
void commit(TransactionStatus status) throws TransactionException
void rollback(TransactionStatus status) throws TransactionException
其用于所有Spring事务管理器的通用接口,如果仅仅处理一个数据源并且用jdbc进行访问,使用DataSourceTransactionManager;如果JTA进行javaEE应用服务器上的事务管理,就应该使用JtaTransactionManager,其对于分布式事务是合适的。如果使用ORM框架访问数据库,应该选取对应的事务管理器,如HibernateTransactionManager或JpaTransactionManager。可以使用IoC容器来进行配置,如
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
2.编程式事务管理
Spring的事务管理器提供一个技术独立的API,通过getTransaction()启动新事务,通过调用commit()和rollback()方法管理事务。类似如下代码:
...
TransactionDefinition def = new DefaultTransactionDefintion();
TransactionStatus status = transactionManager.getTransaction(def);
......
transactionManager.commit(status);
...
transactionManager.rollback(status);
...
配置如下:
<beans>
<bean id="transactionManager" class="org.springframework.jdbc.datasourdce.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="xxxx" class="yyyyy>
...
<property name="transactionManager" ref="transactionManager"/>
</bean>
</beans>
Spring还提供了事务模板 TransactionTemplate帮助控制整个事务管理过程和事务异常处理。只要在实现TransactionCallback<T>接口的回调类里封装代码,并传递给TransactionTemplate的execute方法执行就可以了。使用如下:
...
private TransactionTemplate transactionTemplate ;
...
transactionTemplate.execute(new TransactionCallbackWithoutResult(){
protected void doInTransactionWithoutResult(TransactionStatus status){
....
});
...
如果想使用IoC容器注入transactionTemplate的话,则为其提供set方法,配置如下:
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate>
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="xxxx" class="yyyyy">
...
<property name="transactionTemplate" ref="transactionTemplate"/>
...
</bean>
3.声明式事务管理
Spring 2.x之后使用AOP方法进行声明式管理事务,通过tx schema中定义的<tx:advice>元素来配置,因此事先要在xml文件中加入schema的约束。该方式对应基于Schema的aop配置,需在<aop:config>元素中声明一个通知器(Advisor),将通知与切入点关联。如下配置:
<tx:advice id="xyzTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="xyz"/>
</tx:attributes>
</tx:advice>
...
<aop:config>
...
<aop:advisor advice-ref="xyzTxAdvice" pointcut-ref="zyz" />
...
</aop:config>
<bean id="transactionManager" class="org.springframework.jdbc.datasourdce.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
除此之外,Spring允许仅通过@Transactional注解你的事务性方法,并且启用<tx:annotation-driven>元素声明事务。最好只注解公开方法。
配置如下:
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasourdce.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
4.设置事务属性
传播属性 事务传播在事务性方法被另一个方法调用时发生的,其由事务属性propagation指定,spring定义了7中传播行为,这些行为在org.springframework.transaction.TransactionDefinition接口中定义。如下:
REQUIRED:如果现有的事务正在进行,当前方法应该在这个事务中运行,否则重新开启一个事务,并在自己的事务中运行。
REQUIRED_NEW:当前方法必须启动新事务,并在自己的事务中运行,如果现有的事务正在运行,则应该挂起。
SUPPORTS:如果现有事务正在运行,当前方法应该运行在该事务中,否则,它没有必要运行在事务中。
NOT_SUPPORTED:当前方法不应该运行在事务中。如果现在事务正在进行,它应该挂起。
MANDATORY:当前方法必须运行一个事务中。如果没有事务在进行中,将抛出一个异常。
NEVER:当前方法不应该运行于事务中。如果现有事务在运行中,将抛出异常。
NESTED: 现有事务不应该运行于事务中。如果现有事务在运行中,将抛出异常。
这些传播行为,并不是所有的事务管理器都支持的,而且不同的隔离级别,也会限制传播行为。 传播属性的配置三种如下:
<tx:advice>
<tx:attributes>
<tx:method name="..." propagation="REQUIRED"/>
</tx:attributes>
</tx:advice> <property name="transactionAttributes">
<props>
<prop key="...">PROPAGATION_REQUIRED</prop>
</props>
</property> DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
隔离属性 当相同应用或者不同应用的多个失误同时在同一数据集上操作时,可能发生许多不可预期的问题,必须至少能够幻想隔离的预期方式。并发产生的问题有:
脏数据:两个事务,后一个事务读取到了前一个事物还没有提交的字段,若前一个事务出现回滚,则后一个事务读取的字段是无效的。
不可重复读: 两个事务,前一个事务读取一个字段,后一个事务更新了这个字段,前一事务再去读相同的字段,数据不一致。
幻读:两个事务,前一个事务读取一些数据行,后一个事务新添加了数据行,前一个事务再去读,读到更多的数据行。
更新丢失:两个事务,更新同一个字段数据,前一个事务进行提交,后一个事务之后进行提交,前一个事务的更新会被覆盖掉。
理论上应该完全隔离,但是会对性能造成很大的影响,因为事务是顺序进行的。Spring支持5中隔离级别,这些级别在org.springframework.transaction.transaction.TransactionDefinition 接口中定义。如下:
DEFAULT:使用低层数据库的默认隔离级别,对于大多数数据库来说,默认的隔离级别是READ_COMMITTED
READ_UNCOMMITTED:允许事务读取其他事物未提交修改。可能发生脏读、不可重复读和幻读,该级别下读操作不加S锁
READ_COMMITTED:仅允许事务读取已经提交的修改。能避免脏读,但不可重复读和幻读可能发生,该级别下读操作需要加S锁,但在语句执行完之后释放S锁
REPEATABLE_READ:确保食物能够多次从一个字段读到相同值,在其他事务的更新被禁止。能避免脏读和不可重复读,幻读可能发生,该级别下读操作需要加S锁,但在事务提交之后才释放S锁。
SERIALIZABLE:确保一个事物能从表中多次读取相同的行。在事务期间,其他事务的行为均被禁止。能避免所有并发问题,但性能低,在该级别下又添加了一个范围锁,保证事务的两次查询一样。
配置如下:
<tx:advice ...>
<tx:attributes>
<tx:method name="*" isolation="REPEATABLE_READ"/>
</tx:attributes>
</tx:advice> <property name="transactionAttributes">
<props>
<prop key="...">
PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ
</prop>
</props>
</property> DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
Rollback、超时和只读事务属性 我们有时候需要自己设置回滚异常,而不是遇到异常或者错误的时候才让事务回滚。通过设置rollback事务属性来指定。若不指定则按照默认规则处理。如果事务长时间占用资源势必会影响性能,因此同样需要优化和改进引用性能,timeout事务属性表示事务在被强制回滚之前存活的时间,read-only属性表示该事务仅仅读取而不更新数据。这些配置如下:
可直接在@Transactional注解中设置rollbackFor和noRollbackFor属性定义,属性被声明为Class[],可以指定超过一个异常,也支持直接设置timeout和readOnly。
其他如下:
<tx:advice ...>
<tx:attributes>
<tx:method name="...">
rollback-for="java.io.IOException"
no-rollback-for="java.lang.ArithmeticException"/>
timeout="30"
read-only="true"
</tx:method>
</tx:attributes>
</tx:advice> <property name="transactionAttributes">
<prop key="...">
PROPAGATION_REQUIRED,-java.io.IOException,+java.lang.ArithmeticException,timeout_30,readOnly
</prop>
</property> RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();
attr.getRollbackRules().add(new RollbackRuleAttribute(IOException.class));
attr.getRollbackRules().add(new NoRollbackAttribute(ArithmeticException));
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setTimeout(30);
def.setReadOnly(true);
Spring3之事务管理的更多相关文章
- Spring3数据库事务管理机制
Spring对事务的解决办法其实分为2种:编程式实现事务,AOP配置声明式解决方案. http://jinnianshilongnian.iteye.com/blog/1496953 Spring提供 ...
- spring3.0事务管理配置
转载:http://war-martin.iteye.com/blog/1396335 第一种配置方法:基于XML的事务管理 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的 ...
- Spring3 (事务管理)
简介: 1.事务管理.2.整合Junit.3.整和Web 1 事务管理 1.1 回顾事务 l 事务:一组业务操作ABCD,要么全部成功,要么全部不成功. l 特性:ACID 原子性 ...
- [转]Spring3核心技术之事务管理机制
原文地址:http://chouyi.iteye.com/blog/1675199 Spring对事务的解决办法其实分为2种:编程式实现事务,AOP配置声明式解决方案. http://jinnians ...
- 跟我学Spring3(9.2):Spring的事务之事务管理器
原文出处: 张开涛9.2.1 概述 Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口PlatformTransactionManage ...
- Spring3.0配置多个事务管理器(即操作多个数据源)的方法
大多数项目只需要一个事务管理器.然而,有些项目为了提高效率.或者有多个完全不同又不相干的数据源,最好用多个事务管理器.机智的Spring的Transactional管理已经考虑到了这一点,首先分别定义 ...
- Spring的事务管理
事务 事务:是逻辑上一组操作,要么全都成功,要么全都失败. 事务特性(ACID) 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 隔离性:一个事务执行的时候,不应该受到其他事务的打扰 ...
- Spring第13篇—–Spring整合Hibernate之声明式事务管理
不容置疑的我们可以知道Spring的事务管理是通过AOP(AOP把我们的事务管理织入到我们的业务逻辑里面了)的方式来实现的,因为事务方面的代码与spring的绑定并以一种样板式结构使用.(面向切面编程 ...
- spring的annotation-driven配置事务管理器详解
http://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html ——————————————————————————————————————————————— ...
随机推荐
- JS组件Bootstrap实现弹出框和提示框效果代码
这篇文章主要介绍了JS组件Bootstrap实现弹出框和提示框效果代码,对弹出框和提示框感兴趣的小伙伴们可以参考一下 前言:对于Web开发人员,弹出框和提示框的使用肯定不会陌生,比如常见的表格新增和编 ...
- 《深入Java虚拟机学习笔记》- 第16章 控制流
<深入Java虚拟机学习笔记>- 第16章 控制流
- 5、四大组件之一-Activity与Intent
一.Activity的定义及作用 1)官方定义:Activity是Android应用程序提供交互界面的一个重要组件 . 也是Android最重要的组件之一 2)Activity是业务类 , 是承载应用 ...
- MyEclipse 下用link 方式安装插件
N年之前,也是Java出身,后来转DBA,Java 就忘的差不多了. 最近计划好好研究下Python,还是选用MyEclipse 这个IDE了,多年没敲代码,很多东西都忘记了,做点笔记,备用. M ...
- opencv 在工业中的应用:模板匹配
模板匹配在工业中经常有两个用途,一模板匹配进行产品定位,二根据匹配度来判断是OK的产品还是NG的产品.我用OPENCV做了个模板匹配定位的DEMO. (1)点击打开图像按钮打开一幅图像 (2)点击定义 ...
- 设计模式_Memento_备忘录模式
形象例子: 同时跟几个MM聊天时,一定要记清楚刚才跟MM说了些什么话,不然MM发现了会不高兴的哦,幸亏我有个备忘录,刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存,这样可以随时察看以前的记录啦 ...
- 【译】 AWK教程指南 1前言
前面的话: 这几天写了一个程序,在同一个目录里生成了很多文件,需要统计其中部分文件的总大小,发现经常用到的ls.du等命令都无济于事,我甚至都想到了最笨的方法,写一个脚本:mkdir一个新目录,把要统 ...
- STM32 串口功能 库函数 详解和DMA 串口高级运用(转载)
数据传输时要从支持那些相关的标准?传输的速度?什么时候开始?什么时候结束?传输的内容?怎样防止通信出错?数据量大的时候怎么弄?硬件怎么连接出发,当然对于stm32还要熟悉库函数的功能 具起来rs232 ...
- php中的字符串和正则表达式
一.字符串类型的特点 1.PHP是弱类型语言,其他数据类型一般都可以直接应用于字符串函数操作. 1: <?php //输出345 //输出345 //先查找hello常量,若没找到,将hello ...
- NOIP2006 作业调度方案
1. 作业调度方案 (jsp.pas/c/cpp) [问题描述] 我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成.每个工件的每道工 ...