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(); } }
Spring事物的配置样式如下:
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> <bean id="myProxy" parent="baseTransactionProxy"> <property name="target" ref="myTarget"/> </bean>
可以看出TransactionProxyFactoryBean是Spring事物的入口;在TransactionProxyFactoryBean中声明了
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
并将TransactionManager, TransactionAttributes赋值给了transactionInterceptor拦截器。该类继承了AbstractSingletonProxyFactoryBean,而AbstractSingletonProxyFactoryBean又实现了InitializingBean接口;在bean初始化完成后会调用 AbstractSigletonProxyFactoryBean的afterPropertiesSet方法。在该方法中又调用了TransactionInterceptor的createMainInterceptor方法
// Add the main interceptor (typically an Advisor).
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
protected Object createMainInterceptor() { this.transactionInterceptor.afterPropertiesSet(); if (this.pointcut != null) { return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor); } else { // Rely on default pointcut. return new TransactionAttributeSourceAdvisor(this.transactionInterceptor); } }
至此就完成了Spring事物通知器的注入。
后续的处理就和普通的AOP一样,我们都知道在Spring AOP中是通过JDK的动态代理和CGLIB实现的
JdkDynamicAopProxy.invoke 方法是AOP方法调用的入口。在该方法中有:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
如果当前方法需要在事物中运行,在中会调用到TransactionInterceptor.invoke()方法。
public Object invoke(final MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } }); }
调用父类中的方法是先了事物处理
protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; } else { // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus status) { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceedWithInvocation(); } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. return new ThrowableHolder(ex); } } finally { cleanupTransactionInfo(txInfo); } } }); // Check result: It might indicate a Throwable to rethrow. if (result instanceof ThrowableHolder) { throw ((ThrowableHolder) result).getThrowable(); } else { return result; } } catch (ThrowableHolderException ex) { throw ex.getCause(); } } }