Spring 中的事务处理
Spring 支持编程式事务和声明是事务处理。 编程式事务管理通过在业务方法中嵌入控制事务提交和回滚的事务管理代码来实现。 声明式事务管理时通过AOP框架支持的。
Spring 核心事务管理抽象基于PlatformTransactionManager接口。它封装了一组用户事务管理的技术独立方法。TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
Spring 对这个接口提供了多种内建实现:
JtaTransactionManager
JmsTransactionManager
JpaTransactionManager
JdoTransactionManager
HibernateTransactionManager
DataSourceTransactionManager
Spring 事务的传播属性有”
REQUIRED: 如果现有事务正在运行,当前方法应该在事务中运行,否则它将启动新的事务,并在自己的事务中运行。
REQUIRES_NEW:当前方法必须启动新事务,并在自己的事务中运行;如果现有的事务正在运行,它将被挂起。
SUPPORTS:如果现有事务重在运行,当前方法应该运行在事务中,否则它没有必要运行在事务中。
NOT_SUPPORTED:当前方法不应该运行在事务中,如果现有事务正在运行则,它将被挂起
MANDATORY:当前方法必须运行在一个事务中,如果没有事务在进行中,它将抛出一个异常;
NEVER:当前方法不应该运行在事务中,如果现有事务正在运行中,将抛出一个异常。
NESTED:如果现有事务正在运行,当前方法应该运行在嵌套事务中,否则,它应该启动一个新的事务并运行在自己的事务中。这个功能时Spring 特有的。该行为对批处理特别有用。
事务的隔离:
事务的隔离是由底层数据库引擎实现的而不是Spring 框架实现的。
DEFAULT: 使用底层数据库默认的隔离级别。对于大多数数据库而言,默认的隔离级别是READ_COMMITTED;
READ_UNCOMMITTED: 允许读取其他事务未提交的修改
READ_COMMITTED:运行读取其他事务提交的修改
REPEATABLE_READ:确保事务能够多次从一个字段中读取到同一个值。在本事务期间,其他事务更细被禁止。
SERIALIZABLE:确保一个事务从表中多次读取相同的行。在事务期间,其他事务对该表的插入,更新,删除将全部被禁止。
编程式事务管理:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd
">
<context:component-scan base-package="com.david.*" />
<aop:aspectj-autoproxy />
<!-- 定义jdbc模板类 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 事务模板 -->
<bean id="transactionTemlate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean
class="org.springframework.validation.beanvalidation.BeanValidationPostProcessor" />
<!-- 方法验证后处理器 -->
<bean
class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor" />
</beans>
/**
* @see com.david.biz.service.BookService#addBook(com.david.common.domain.Book)
*/
public boolean addBook(final Book book) throws Exception {
transactionTemplate.execute(new TransactionCallback<Boolean>() {
public Boolean doInTransaction(TransactionStatus status) {
try {
bookDao.insert(book);
return Boolean.TRUE;
} catch (Exception e) {
// rollback
status.setRollbackOnly();
}
return Boolean.FALSE;
}
});
}
使用声明式事务管理:
/**
*
* @see com.david.biz.service.BookService#addBook()
*/
@Transactional(propagation = Propagation.REQUIRED)
public void addBook(Book book) throws Exception {
bookDao.insert(book);
throw new UnRollbackException("受检查异常是不会回滚事务的");
}
默认情况下,只有非受控异常也就是RuntimerException 和Error类型的异常将导致事务回滚,而受控异常则不会回滚。但是可以通过设置rollbackFor 和noRollbackFor属性处理受控异常的回滚。
public class AService{
private BService b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod(){
b.bmethod();
}
}
public class BService{
@Transactional(propagation = Propagation.REQUIRED)
public void bMethod(){
}
}
如果事务的传播属性是REQUIRED, 如果b的事务已经提交后,在a中发生异常则会连同b一起回滚,因为这个两个使用的是同一个事务。
如果事务的传播属性是REQUIRES_NEW, 则a 中发生异常不会响应到b的事务提交,因为b和a是两个不同的是事务
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
/**
* 指定事物限定符,用于确定目标事物管理器,匹配指定具体的PlatformTranscationManager bean定义的指定的值或名字
*/
String value() default "";
/**
* 设置事物的传播属性,默认是REQUIRED
*/
Propagation propagation() default Propagation.REQUIRED;
/**
*设置事物的隔离级别
*/
Isolation isolation() default Isolation.DEFAULT;
/**
* 设置事物超时时间
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* 如果是只读事务则设置为true,默认值是false
*/
boolean readOnly() default false;
/**
* 定义0个或多个事务回滚的异常类型
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* 指定0个或多个事务回滚的异常名称
*/
String[] rollbackForClassName() default {};
/**
* 排除不需要回滚的易异常
*/
Class<? extends Throwable>[] noRollbackFor() default {};
/**
* 排除不需要回滚的异常名称
*/
String[] noRollbackForClassName() default {};
}
在Spring的事务处理中是不识别@Transation 注解的,首先将@Transcation注解解析为Spring 事务系统能够识别的RuleBaseTranscationAttribute
/**
* 解析Transcation事务注解的策略
*/
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
Transactional ann = AnnotationUtils.getAnnotation(ae, Transactional.class);
if (ann != null) {
return parseTransactionAnnotation(ann);
}
else {
return null;
}
}
/**
*
**/
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
// 创建一个RuleBaseTranscationAttribute对象
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
//将注解的事务传播属性设置到RuleBasedTranscationAttribute对象中
rbta.setPropagationBehavior(ann.propagation().value());
//将事务注解的事务隔离级别设置到RuleBasedTranscationAttribute对象中
rbta.setIsolationLevel(ann.isolation().value());
//设置事务超时时间
rbta.setTimeout(ann.timeout());
// 设置只读属性
rbta.setReadOnly(ann.readOnly());
//限定事务管理器
rbta.setQualifier(ann.value());
//创建事务事务会馆条件参数队列
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
//获取事务注解中配置的回滚异常类
Class[] rbf = ann.rollbackFor();
// 根据配置的异常类创建RollbackRuleAttribute
for (Class rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
// 获取事务注解配置的回滚异常名称
String[] rbfc = ann.rollbackForClassName();
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//获取事务注解配置的不回滚异常类
Class[] nrbf = ann.noRollbackFor();
for (Class rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//获取事务注解配置的不回滚异常名称
String[] nrbfc = ann.noRollbackForClassName();
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//设置回滚条件
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
// 重写equals的同时重写hashCode
@Override
public boolean equals(Object other) {
return (this == other || other instanceof SpringTransactionAnnotationParser);
}
@Override
public int hashCode() {
return SpringTransactionAnnotationParser.class.hashCode();
}
}