/**什么异常时才回滚**/
Spring事务策略
由PlatformTransactionManager接口定义:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction(..)方法根据一个类型为 TransactionDefinition 的参数返回一个 TransactionStatus 对象。返回的 TransactionStatus 对象可能代表一个新的或已经存在的事务。
TransactionDefinition接口指定:
事务隔离:当前事务和其它事务的隔离的程度。例如,这个事务能否看到其他事务未提交的写数据?
事务传播:通常在一个事务中执行的所有代码都会在这个事务中运行。但是,如果一个事务上下文已经存在,有几个选项可以指定一个事务性方法的执行行为:例 如,简单地在现有的事务中继续运行(大多数情况);或者挂起现有事务,创建一个新的事务。Spring提供EJB CMT中常见的事务传播选项。
事务超时: 事务在超时前能运行多久(自动被底层的事务基础设施回滚)。
只读状态: 只读事务不修改任何数据。只读事务在某些情况下(例如当使用Hibernate时),是一种非常有用的优化。
在TransactionDefinition接口中定义了五个不同的事务隔离级别
ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应
ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
事物传播
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
TransactionStatus 接口
为处理事务的代码提供一个简单的控制事务执行和查询事务状态的方法。
public interface TransactionStatus {
boolean isNewTransaction();
void setRollbackOnly();
boolean isRollbackOnly();
}
PlatformTransactionManager以TransactionStatus处理事务,TransactionStatus 这个接口有三个方法
isNewTransaction() ,isRollbackOnly(),setRollbackOnly()。PlatformTransactionManager就是根据前两个方法决 定是否要创建一个新事务,是要递交还是回滚。总结上面所说的,spring的事务由PlatformTransactionManager管 理,manager最后调用事务源的方法来实现一个事务过程。而manager通过TransactionStatus 来决定如何实现。
声明式事务管理:
在理解Spring的声明式事务管理方面最重要的概念是:Spring的事务管理是通过AOP代理实现的。代理对象与事务元数据结合产生了一个AOP代 理,它使用一个PlatformTransactionManager 实现品配合TransactionInterceptor,在方法调用前后实施事务。
……
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
……
'transaction-manager' 属性被设置为一个指向 PlatformTransactionManager bean的名字(这里指 'txManager'), 该bean将会真正管理事务。事实上,如果 PlatformTransactionManager bean的名字是 'transactionManager' 的话,你的事务通知(<tx:advice/>)中的 'transaction-manager' 属性可以忽略。否则你则需要像上例那样明确指定。
声明式配置控制事务的回滚:
Spring框架的事务基础架构代码将默认地只在抛出运行时和unchecked exceptions时才标识事务回滚。也就是说,当抛出一个 RuntimeException或其子类例的实例时。从事务方法中抛出的Checked exceptions将不被标识进行事务回滚。
可以配置哪些 Exception类型将被标识进行事务回滚。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
不想在异常抛出的时候回滚事务,就可以使用“不回滚规则”。
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
编程式 方式来指定回滚事务
public void resolvePosition() {
try {
// some business logic...
} catch (NoProductInStockException ex) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
<tx:advice/> 有关的设置:
-
事务传播设置 是 REQUIRED
-
隔离级别是DEFAULT
-
事务是 读/写
-
事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
-
任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
<tx:method/> 有关的设置
属性 是否需要? 默认值 描述name | 是 | 与事务属性关联的方法名。通配符(*)可以用来指定一批关联到相同的事务属性的方法。 如:'get*'、'handle*'、'on*Event'等等。 |
|
propagation | 不 | REQUIRED | 事务传播行为 |
isolation | 不 | DEFAULT | 事务隔离级别 |
timeout | 不 | -1 | 事务超时的时间(以秒为单位) |
read-only | 不 | false | 事务是否只读? |
rollback-for | 不 | 将被触发进行回滚的 Exception(s);以逗号分开。 如:'com.foo.MyBusinessException,ServletException' |
|
no-rollback-for | 不 | 不 被触发进行回滚的 Exception(s);以逗号分开。 如:'com.foo.MyBusinessException,ServletException' |
@Transactional 注解
通过一 行xml配置就可以使它具有事务性
<tx:annotation-driven transaction-manager="txManager"/>
可以被应用于接口定义和接口方法、类定义和类的 public 方法上。 然而,请注意只是使用 @Transactional 注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,系统也不会报错, 但是这个被注解的方法将不会执行已配置的事务设置。另外,Spring团队的建议是你只在具体的类上使用 @Transactional 注解,而不要注解在接口上。
<tx:annotation-driven/> 设置
属性 默认值 描述transaction-manager | transactionManager | 使用的事务管理器的名字。只有像在上面的例子那样,事务管理器不是 transactionManager的情况下才需要。 |
mode | proxy | 默认的模式“proxy”会用Spring的AOP框架来代理注解过的bean(就像在前面讨论过的那样, 下面代理的语义只对通过代理传递过来的方法调用起效)。 另一种可行的模式"aspectj"会使用Spring的AspectJ事务切面来编织类(通过修改目标对象的字节码应用到任何方法调用上)。 AspectJ织入需要在classpath中有spring-aspects.jar这个文件,并且启用装载时织入 (或者编译时织入). (关于如何设置装载时编织的详情请参见 Section 6.8.4.5, “Spring配置” ) |
proxy-target-class | false | 只对代理模式有效。决定为那些使用了@Transactional注解的类创建何种事务代理。 如果 "proxy-target-class" 属性被设为 "true", 那么基于类的代理就会被创建。如果 "proxy-target-class"属性被设为"false" 或者没设,那么基于接口的标准JDK代理就会被创建 (关于不同代理类型的解释请参见 Section 6.6, “代理机制” ) |
order | Ordered.LOWEST_PRECEDENCE | 定义事务通知的顺序会作用到使用@Transactional注解的bean上。 更多的关于AOP通知顺序的定义可以在章节(参见 Section 6.2.4.7, “通知顺序”)。 请注意如果不指定任何顺序将会把决定权交给AOP子系统。 |
proxy-target-class" 属性 控制了有什么类型的事务性代理会为使用@Transactional 来注解的类创建代理。 如果"proxy-target-class" 属性被设为"true",那么基于类的代理就会被创建。 如果"proxy-target-class" 属性被设为"false" 或者没设,那么会创建基于接口的标准JDK代理。
默认的 @Transactional 设置如下:
-
事务传播设置是 PROPAGATION_REQUIRED
-
事务隔离级别是 ISOLATION_DEFAULT
-
事务是 读/写
-
事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
-
任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
@Transactional 注解的属性
属性 类型 描述propagation | 枚举型:Propagation | 可选的传播性设置 |
isolation | 枚举型:Isolation | 可选的隔离性级别(默认值:ISOLATION_DEFAULT) |
readOnly | 布尔型 | 读写型事务 vs. 只读型事务 |
timeout | int型(以秒为单位) | 事务超时 |
rollbackFor | 一组 Class 类的实例,必须是Throwable 的子类 | 一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。 |
rollbackForClassname | 一组 Class 类的名字,必须是Throwable的子类 | 一组异常类名,遇到时 必须 进行回滚 |
noRollbackFor | 一组 Class 类的实例,必须是Throwable 的子类 | 一组异常类,遇到时 必须不 回滚。 |
noRollbackForClassname | 一组 Class 类的名字,必须是Throwable 的子类 | 一组异常类,遇到时 必须不 回滚 |
编程式事务管理
Spring提供两种方式的编程式事务管理:
使用 TransactionTemplate
直接使用一个 PlatformTransactionManager 实现
TransactionTemplate 采用与Spring中别的 模板 同样的方法, 如 JdbcTemplate 。它使用回调机制,将应用代码从样板式的资源获取和释放代码中解放出来, 这样写出的代码是目的驱动的,把精力集中在开发者想要做的事情上。
有返回值
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
不需要返回值
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
回调方法内的代码可以通过调用 TransactionStatus 对象的 setRollbackOnly() 方法来回滚事务。
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessExeption ex) {
status.setRollbackOnly();
}
}
});
指定事务设置
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30);
}
}
XML配置
<bean id="sharedTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>"
使用PlatformTransactionManager
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// execute your business logic here
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
参考:
http://www.javaeye.com/topic/11190
http://www.javaeye.com/topic/199813
http://www.javaeye.com/topic/78674
http://www.javaeye.com/topic/35907
http://hi.baidu.com/brnz/blog/item/85c78b39831086e414cecb77.html