Spring事务管理--25
事务:指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败事务的四大特性:
原子性:指的是事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生; 一致性:指的是事务前后数据的完整性必须保持一致; 隔离性:指的是多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离(通过在数据库中设置隔离级别); 持久性:指的是一个事务一旦被提交,它对数据库中数据的改变是永久性的,即使数据库发生故障也不应该对其有任何影响。
Spring事务管理高层抽象主要有3个接口:
1.platform TransactionManager 平台事务管理(主要是处理事务的提交,回滚等。) 2.TransactionDefinition 事务定义信息(隔离级别、传播行为、超时、只读) 3.TransactionStatus 事务具体运行状态(已经提交?是否有保存点呀?是否新的事物?) PlatformTransactionManager 根据 TransactionDefinition 进行事务管理,管理过程中事务存在多种状态,每个状态信息通过 TransactionStatus 表示
Spring为不同的持久化框架提供不同的PlatformTransactionManager接口实现
数据库事务的隔离四种隔离级别:
安全等级由小到大依次是: read_uncommitted 脏读、不可重复读、幻读都有可能发生 read_committed 避免发生脏读 repeatable_read 避免发生脏读,不可重复读 serializble 串行的以队列的形式,都可避免 脏读:一个事务在读取到另一个事务把以改变,未提交的事务,数据回滚后,可能出现无效的数据 不可重复读:在同一个事务中,事务中前后查询的数据不一致,可能是两次查询中间有事务做了更新数据的操作。 幻读:一个事务在查询的过程中,先后查询出的结果不一致,中间可能有另一个事务做了数据的插入。spring事务管理提供了一个isolation default ,根据持久层默认的隔离级别
oracle----read_committed mysql----repeatable_read
==================================================================================================================================事务的传播行为有七种,又分为三类:第一类共同点:如果 A 方法中有事务,则调用 B 方法时就用该事务,即:A和B方法在同一个事务中。PROPAGATION_REQUIRED:如果 A 方法中没有事务,则调用 B 方法时就创建一个新的事务,即:A和B方法在同一个事务中。PROPAGATION_SUPPORTS:如果 A 方法中没有事务,则调用 B 方法时就不使用该事务。PROPAGATION_MANDATORY:如果 A 方法中没有事务,则调用 B 方法时就抛出异常。第二类共同点:A方法和B方法没有在同一个事务里面。PROPAGATION_REQUIRES_NEW:如果 A 方法中有事务,则挂起并新建一个事务给 B 方法。PROPAGATION_NOT_SUPPORTED:如果 A 方法中有事务,则挂起。PROPAGATION_NEVER:如果 A 方法中有事务,则报异常。第三类:如果 A 方法有的事务执行完,设置一个保存点,如果 B 方法中事务执行失败,可以滚回保存点或初始状态。
事务的传播行为:主要是解决业务层方法之间的相互调用的问题PROPAGATION_NESTED :如果当前事务存在,则嵌套事务执行@重点的三种:PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, PROPAGATION_NESTED。
TransactionStatus接口用来记录事务的状态
该接口定义了一组方法,用来获取或判断事务的相应状态信息. 平台事务管理器(PlatformTransactionManager)会根据TransactionDefinition中定义的事务信息(包括隔离级别、传播行为)来进行事务的管理,在管理的过程中事务可能产生了保存点或事务是新的事务等情况,那么这些信息都会记录在TransactionStatus的对象中.
============================================================================================================================
Spring事务管理
Spring 支持两种方式事务管理
(1)编程式的事务管理
1、在实际应用中很少使用 2、通过 TransatcionTemplate 手动管理(2)使用 XML 配置声明式事务
1、开发中推荐使用(代码侵入性最小) 2、Spring 的声明式事务是通过AOP实现的
转账案例:
编程式的事务控制
①配置事务管理器:TranscationManager,一般在不适用Hibernate的情况下,使用DataSourceTranscationManager,需要注入数据源 ②配置事务管理器的管理事务的模板,如果不配置,需要手动编程事务管理的方法,很麻烦,建议使用spring提供的事务模板方法:transcationTemplate,需要注入事务管理器 ③将TranscationTempalte配置好后,注入到使用的事务的service层的类中,作为属性。 ④在service中,执行transcationTemplate提供的execute方法,方法中进行事务的操作,这个方法中有个参数,transcationcallback,如果事务出现回滚,将会调用这个参数进行操作。
<!-- ==================================1.编程式的事务管理=============================================== -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
public class AccountServiceImpl implements AccountService {
//注入转账的DAO
private AccountDao accountDao;
//注入事务管理的模板
private TransactionTemplate transactionTemplate;
/**
* @param out :转出账号
* @param in :转入账号
* @param money :转账金额
*/
@Override
public void transfer(final String out, final String in, final Double money) {
/*accountDao.outMoney(out, money);
//int i = 1/0;
accountDao.inMoney(in, money);*/
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(out, money);
//int i = 1/0;
accountDao.inMoney(in, money);
}
});
}
基于TransactionProxyFactoryBean的声明式事务管理的方式
这种方式只是简单的使用到了aop的思想,对service对象进行了代理模式的增强,前一章在编程式事务管理器的时候需要在service中注入事务管理器的模板,而现在这种声明式的方法,配置了TransactionProxyFactoryBean,属性对象之一就是原先的service,这就是对目标对象进行代理,除了引用transactionManager之外还需要声明事务的属性,也就是隔离级别、传播行为、是否只读、异常处理等等。
声明式的事务管理(传统方式) 声明式的事务管理是基于AOP的思想完成的.因此需要引用Spring AOP开发需要用到的jar包. 传统的声明式事务管理:1.配置事务管理器
<!-- ==================================2.使用XML配置声明式的事务管理(原始方式)=============================================== --> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置业务层的代理 --> <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 配置目标对象 --> <property name="target" ref="accountService" /> <!-- 注入事务管理器 --> <property name="transactionManager" ref="transactionManager"></property> <!-- 注入事务的属性 --> <property name="transactionAttributes"> <props> <!-- prop的格式: * PROPAGATION :事务的传播行为 * ISOTATION :事务的隔离级别 * readOnly :只读 * -EXCEPTION :发生哪些异常回滚事务 * +EXCEPTION :发生哪些异常不回滚事务 --> <prop key="transfer">PROPAGATION_REQUIRED</prop> <!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> --> <!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> --> </props> </property> </bean> </beans>
2.引用TransactionProxyFactoryBean,TransactionProxyFactoryBean是采用动态代理完成事务管理的,直接配置一个TransactionProxyFactoryBean即可.
TransactionProxyFactoryBean中有4个属性,分别是proxyInterfaces、target、transactionManager、transactionAttributes属性.
proxyInterfaces:该属性配置需要代理的接口
target:该属性配置proxyInterfaces中指定接口的实现类
transactionManager:该属性指定一个TransactionManager
transactionAttributes:该属性指定需要设置proxyInterfaces的接口中需要添加事务的的方法.支持<props>多个配置.因为此属性是Properties类型(java.util.Properties).此类型是键值对的形式.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class TransactionTest {
/**
* 一定要注入代理类:因为代理类进行增强的操作
*/
//@Resource(name="accountService")
@Resource(name="accountServiceProxy")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("aaa", "bbb", 200d);
}
}
基于aspectj(切面)配置:
这是一种经常使用的事务声明方式 在配置文件中配置完dataSourceTransactionManager之后,使用spring提供的命名空间为<tx:advice>的标签给事务配置属性,比如传播行为、隔离级别、异常处理等等,这是一种基于面向切面的配置方式,可以在任何想要事务处理的地方使用,其次就是使用aop的声明式方式完成advice和pointcut的横切面配置,注意advice引用的就是<tx>标签配置的事务,pointcut是切入的方法
<!-- ==================================3.使用XML配置声明式的事务管理,基于tx/aop=============================================== -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务的通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
propagation :事务传播行为
isolation :事务的隔离级别
read-only :只读
rollback-for:发生哪些异常回滚
no-rollback-for :发生哪些异常不回滚
timeout :过期信息
-->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
</beans>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class TransactionTest {
/**
* 一定要注入代理类:因为代理类进行增强的操作
*/
@Resource(name="accountService")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("aaa", "bbb", 200d);
}
}
基于注解的声明式事务管理方式:
配置完事务管理器之后,只需要在配置文件中使用<tx:annotation-driver transactionManager=“transactionManager”>
将基于事务注解的方式打开,在需要注解管理的类上添加@Transactional以达到控制事务的目的
<!-- ==================================4.使用注解配置声明式事务============================================ -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
/**
* @author admin
*@Transactional中的的属性
*propagation :事务的传播行为
*isolation :事务的隔离级别
*readOnly :只读
*rollbackFor :发生哪些异常回滚
*noRollbackFor :发生哪些异常不回滚
*rollbackForClassName 根据异常类名回滚
*/
@Transactional
public class AccountServiceImpl implements AccountService {
//注入转账的DAO
private AccountDao accountDao;
/**
* @param out :转出账号
* @param in :转入账号
* @param money :转账金额
*/
@Override
public void transfer( String out, String in, Double money) {
accountDao.outMoney(out, money);
//int i = 1/0;
accountDao.inMoney(in, money);
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
spring事务管理的几种实现方式:
1:编程式的事务管理 手动为每个事务管理的类编写增强的代码(基本上不用) 2:声明式的事务管理 一:基于transctionProxyFactoryBean的事务管理 基本上不用,要为每个业务层的类配置事务属性,不利于代码的维护 二:基于AspectJ的XML的声明式事务管理 是整合AOP的方式,以tx:adcvice的方式配置 配置切入点跟切入面。 企业级应用开发中使用较多。 三:基于spring注解的方式 配置简单,只需要开启spring的注解驱动,以annotion的方式,但是需要在每个业务层的类加上tansctional的注解。 里面配置事务的相关行为属性, 用的也多。 spring的四种注入方式: 1:set方法注入 2:构造器注入 3:工厂方法的注入 4:抽象工厂方法的注入 大多数情况下用前面两种,注意事项: spring容器创建的对象默认为单例,如果需要多实例的类,则在bean属性里面配置一个scope="prototype"的属性