Spring 事务
分类
Spring可以支持编程式事务和声明式事务。
编程式事务
实现
Spring使用事务管理器,每个不同平台的事务管理器都实现了接口:PlatformTransactionManager
此接口是事务管理的核心,提供了三个需要实现的函数:
commit(TransactionStatus status) ;
getTransaction(TransactionDefinition definition) ;
rollback(TransactionStatus status) ;
如果我们使用的是JDBC来处理事务,那么这个事务管理器就是DataSourceTransactionManager。
通过Spring文档查找到这个类,发现其需要DataSource这个类。也就是只要实现了javax.sql.DataSource这个接口的类,都可以作为参数传入到DataSourceTransactionManager。
然后,找到 包org.springframework.transaction.support中的 TransactionTemplate。
发现TransactionTemplate中有一个重要的方法:
execute(TransactionCallback action) ;
就是利用这个方法,我们可以在这个方法中添加事务。
这个方法需要传入参数 TransactionCallback。
TransactionCallback,顾名思义,就是事务回调然后查到TransactionCallback。
发现这是一个接口(这也必须是接口,因为任务都是自己具体定义的)
里面只有一个方法:
doInTransaction(TransactionStatus status) ;
很明显,就是在一个事务中需要做的事情都包括这这个方法中了。
而这个doInTransaction 又传入了一个参数,这次是 TransactionStatus,继续顾名思义,也就是事务状态。
查询下去,这个 TransactionStatus 还是一个接口。
是否需要返回值
void dolnTransactionWithoutResult(TransactionStatus status)该方法与dolnTransaction 的效果非常相似,区别在于该方法没有返回值,即事务执行体无须返回值。
声明式事务
-
声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional 注解的方式。注释配置是目前流行的使用方式,因此本文将着重介绍基于@Transactional 注解的事务管理。
-
Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝自由切换的。Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口。
实践
XML
<!-- (必须):事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
<property name="transactionManager" ref="transactionManager" />
<!--ISOLATION_DEFAULT 表示由使用的数据库决定 -->
<property name="isolationLevelName" value="ISOLATION_DEFAULT"/>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
代码
try {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
public void doInTransactionWithoutResult(TransactionStatus ts) {
Service.batchUpdate(DOList);
Service.edit(Bill);
}
});
} catch (Exception e) {
logger.error("Service.batchCreat or Service.create error transaction "
+ "rollback");
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
public void doInTransactionWithoutResult(TransactionStatus ts) {
Service.batchUpdate(DOList);
Service.edit(Bill);
}
});
}
checked异常和unchecked异常
这里之所以让大家清楚checked异常和unchecked异常概念,是因为:
Spring使用声明式事务处理,默认情况下,如果被注解的数据库操作方法中发生了unchecked异常,所有的数据库操作将rollback;如果发生的异常是checked异常,默认情况下数据库操作还是会提交的。
checked异常:
表示无效,不是程序中可以预测的。比如无效的用户输入,文件不存在,网络或者数据库链接错误。这些都是外在的原因,都不是程序内部可以控制的。
必须在代码中显式地处理。比如try-catch块处理,或者给所在的方法加上throws说明,将异常抛到调用栈的上一层。
继承自java.lang.Exception(java.lang.RuntimeException除外)。
unchecked异常:
表示错误,程序的逻辑错误。是RuntimeException的子类,比如IllegalArgumentException, NullPointerException和IllegalStateException。
不需要在代码中显式地捕获unchecked异常做处理。
继承自java.lang.RuntimeException(而java.lang.RuntimeException继承自java.lang.Exception)。
使用注意事项
-
通过 元素的 “proxy-target-class” 属性值来控制是基于接口的还是基于类的代理被创建。如果 “proxy-target-class” 属值被设置为 “true”,那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 属值被设置为 “false” 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。
-
@Transactional 的事务开启 ,或者是基于接口的 或者是基于类的代理被创建。所以在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的
网友评论