1、事物的定义和特性java
事物表明的是一个操做集合。也就是一连串的操做为一个最小单元不可分割(原子性),这一连串的操做要么所有成功要不所有失败(一致性),每个操做集合互不干扰(隔离性),操做集合的全部操做完成后数据必须以一种持久性方式存储起来(持久性)。spring
2、Spring的事务管理express
Spring的事务管理分为编程式事物和声明式事物。编程
一、编程式事物管理框架
基于底层API的编程式事物管理学习
根据PlateformTransactionManger、TransactionDefinition和TransactionStatus这三个核心接口完成 编程式事物管理。编码
基于底层API的事物管理代码示例spa
1 public class BankServiceImpl implements BankService { 2 private BankDao bankDao; 3 private TransactionDefinition txDefinition; 4 private PlatformTransactionManager txManager; 5 ...... 6 public boolean transfer(Long fromId, Long toId, double amount) { 7 TransactionStatus txStatus = txManager.getTransaction(txDefinition); 8 boolean result = false; 9 try { 10 result = bankDao.transfer(fromId, toId, amount); 11 txManager.commit(txStatus); 12 } catch (Exception e) { 13 result = false; 14 txManager.rollback(txStatus); 15 System.out.println("Transfer Error!"); 16 } 17 return result; 18 } 19 }
基于底层API的配置文件代码示例代理
<bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> <property name="txManager" ref="transactionManager"/> <property name="txDefinition"> <bean class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/> </bean> </property> </bean>
基于TransactionTemplate的编程式事物管理code
这种是上面的简化版
public class BankServiceImpl implements BankService { private BankDao bankDao; private TransactionTemplate transactionTemplate; ...... public boolean transfer(final Long fromId, final Long toId, final double amount) { return (Boolean) transactionTemplate.execute(new TransactionCallback(){ public Object doInTransaction(TransactionStatus status) { Object result; try { result = bankDao.transfer(fromId, toId, amount); } catch (Exception e) { status.setRollbackOnly(); result = false; System.out.println("Transfer Error!"); } return result; } }); } }
配置文件示例
<bean id="bankService"
class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
TransactionTemplate 的 execute() 方法有一个 TransactionCallback 类型的参数,该接口中定义了一个 doInTransaction() 方法,一般咱们以匿名内部类的方式实现 TransactionCallback 接口,并在其 doInTransaction() 方法中书写业务逻辑代码。这里可使用默认的事务提交和回滚规则,这样在业务代码中就不须要显式调用任何事务管理的 API。doInTransaction() 方法有一个TransactionStatus 类型的参数,咱们能够在方法的任何位置调用该参数的 setRollbackOnly() 方法将事务标识为回滚的,以执行事务回滚。
根据默认规则,若是在执行回调方法的过程当中抛出了未检查异常,或者显式调用了TransacationStatus.setRollbackOnly() 方法,则回滚事务;若是事务执行完成或者抛出了 checked 类型的异常,则提交事务。
TransactionCallback 接口有一个子接口 TransactionCallbackWithoutResult,该接口中定义了一个 doInTransactionWithoutResult() 方法,TransactionCallbackWithoutResult 接口主要用于事务过程当中不须要返回值的状况。固然,对于不须要返回值的状况,咱们仍然可使用 TransactionCallback 接口,并在方法中返回任意值便可。
二、声明式事物管理
Spring 的声明式事务管理在底层是创建在 AOP 的基础之上的。其本质是对方法先后进行拦截,而后在目标方法开始以前建立或者加入一个事务,在执行完目标方法以后根据执行状况提交或者回滚事务。
声明式事务最大的优势就是不须要经过编程的方式管理事务,这样就不须要在业务逻辑代码中掺琐事务管理的代码,只需在配置文件中作相关的事务规则声明(或经过等价的基于标注的方式),即可以将事务规则应用到业务逻辑中。由于事务管理自己就是一个典型的横切逻辑,正是 AOP 的用武之地。Spring 开发团队也意识到了这一点,为声明式事务提供了简单而强大的支持。
声明式事务管理曾经是 EJB 引觉得傲的一个亮点,现在 Spring 让 POJO 在事务管理方面也拥有了和 EJB 同样的待遇,让开发人员在 EJB 容器以外也用上了强大的声明式事务管理功能,这主要得益于 Spring 依赖注入容器和 Spring AOP 的支持。依赖注入容器为声明式事务管理提供了基础设施,使得 Bean 对于 Spring 框架而言是可管理的;而 Spring AOP 则是声明式事务管理的直接实现者,这一点经过清单8能够看出来。
一般状况下,笔者强烈建议在开发中使用声明式事务,不只由于其简单,更主要是由于这样使得纯业务代码不被污染,极大方便后期的代码维护。
和编程式事务相比,声明式事务惟一不足地方是,后者的最细粒度只能做用到方法级别,没法作到像编程式事务那样能够做用到代码块级别。可是即使有这样的需求,也存在不少变通的方法,好比,能够将须要进行事务管理的代码块独立为方法等等。
下面就来看看 Spring 为咱们提供的声明式事务管理功能。
Spring 提供了 TransactionInterceptor 类来实施声明式事务管理功能。
<beans...> ...... <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="bankServiceTarget" class="footmark.spring.core.tx.declare.origin.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <bean id="bankService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="bankServiceTarget"/> <property name="interceptorNames"> <list> <idref bean="transactionInterceptor"/> </list> </property> </bean> ...... </beans>
<beans......> ...... <bean id="bankServiceTarget" class="footmark.spring.core.tx.declare.classic.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <bean id="bankService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="target" ref="bankServiceTarget"/> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean> ...... </beans>
前面两种声明式事务配置方式奠基了 Spring 声明式事务管理的基石。在此基础上,Spring 2.x 引入了 <tx> 命名空间,结合使用 <aop> 命名空间,带给开发人员配置声明式事务的全新体验,配置变得更加简单和灵活。另外,得益于 <aop> 命名空间的切点表达式支持,声明式事务也变得更增强大。
<beans......> ...... <bean id="bankService" class="footmark.spring.core.tx.declare.namespace.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <tx:advice id="bankAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))"/> <aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/> </aop:config> ...... </beans>
若是默认的事务属性就能知足要求,那么代码简化为
<beans......> ...... <bean id="bankService" class="footmark.spring.core.tx.declare.namespace.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <tx:advice id="bankAdvice" transaction-manager="transactionManager"> <aop:config> <aop:pointcut id="bankPointcut" expression="execution(**.transfer(..))"/> <aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/> </aop:config> ...... </beans>
因为使用了切点表达式,咱们就不须要针对每个业务类建立一个代理对象了。另外,若是配置的事务管理器 Bean 的名字取值为“transactionManager”,则咱们能够省略 <tx:advice> 的 transaction-manager 属性,由于该属性的默认值即为“transactionManager”。
除了基于命名空间的事务配置方式,Spring 2.x 还引入了基于 Annotation 的方式,具体主要涉及@Transactional 标注。@Transactional 能够做用于接口、接口方法、类以及类方法上。看成用于类上时,该类的全部 public 方法将都具备该类型的事务属性,同时,咱们也能够在方法级别使用该标注来覆盖类级别的定义。
@Transactional(propagation = Propagation.REQUIRED) public boolean transfer(Long fromId, Long toId, double amount) { return bankDao.transfer(fromId, toId, amount); }
Spring 使用 BeanPostProcessor 来处理 Bean 中的标注,所以咱们须要在配置文件中做以下声明来激活该后处理 Bean
启用处理Bean
<tx:annotation-driven transaction-manager="transactionManager"/>
与前面类似,transaction-manager 属性的默认值是 transactionManager,若是事务管理器 Bean 的名字即为该值,则能够省略该属性。
虽然 @Transactional 注解能够做用于接口、接口方法、类以及类方法上,可是 Spring 小组建议不要在接口或者接口方法上使用该注解,由于这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。若是你在 protected、private 或者默承认见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
基于 <tx> 命名空间和基于 @Transactional 的事务声明方式各有优缺点。基于 <tx> 的方式,其优势是与切点表达式结合,功能强大。利用切点表达式,一个配置能够匹配多个方法,而基于 @Transactional 的方式必须在每个须要使用事务的方法或者类上用 @Transactional 标注,尽管可能大多数事务的规则是一致的,可是对 @Transactional 而言,也没法重用,必须逐个指定。另外一方面,基于 @Transactional 的方式使用起来很是简单明了,没有学习成本。开发人员能够根据须要,任选其中一种使用,甚至也能够根据须要混合使用这两种方式。
若是不是对遗留代码进行维护,则不建议再使用基于 TransactionInterceptor 以及基于TransactionProxyFactoryBean 的声明式事务管理方式,可是,学习这两种方式很是有利于对底层实现的理解。