Spring 事务管理

来源:互联网 发布:图片修复软件免费版 编辑:程序博客网 时间:2024/06/01 18:52

如果你还不熟悉什么是事务?请先看这篇blog熟悉事务的特性。
MySQL (5)事务


Spring中的事务管理

Spring的事务管理中给我提供了3个接口来进行事务管理。

1.PlatformTransactionManager 事务管理器(事务提交,回滚等)
2.TransactionDefinition 事务定义信息(隔离级别,传播行为,是否超时,是否只读等信息)
3.TransactionStatus 事务具体运行状态

Spring的事务管理主要靠三个接口实现,分别是事务管理器(操作事务的提交和回滚操作),事务定义信息(包括事务的传播,隔离,超时和只读),和事务具体运行状态(可以得到事务的具体状态) 三者之间是有关系的,一般先到事务定义信息读取事务的隔离级别,传播行为等信息,然后事务管理器执行提交和回滚操作,最后通过事务运行状态得到事务的具体状态信息。


PlatformTransactionManager

这里写图片描述

PlatformTransactionManager接口中的主要方法

Public interface PlatformTransactionManager{  TransactionStatus getTransaction(TransactionDefinition definition)   throws TransactionException;    //据事务的隔离级别和传播行为,返回当前活动的事务或者产生一个新的事务。   void commit(TransactionStatus status)throws TransactionException;  //提交一个事务,并监视事务状态   void rollback(TransactionStatus status)throws TransactionException;  //回滚}

TransactionDefinition

事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为
事务的传播行为:主要是解决业务层方法之间的相互调用的问题。

这里写图片描述

第一类共同点:如果 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 方法中事务执行失败,可以滚回保存点或初始状态。 (重点)

事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

事务的只读属性
事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。

TransactionDefinition 接口中定义的主要方

public interface TransactionDefinition{    int getIsolationLevel();  //获取隔离级别    int getPropagationBehavior();  //获取传播行为    int getTimeout();        //获取超时时间    boolean isReadOnly();   //是否只读}

TransactionStatus

平台事务管理器(PlatformTransactionManager)会根据TransactionDefinition中定义的事务信息(包括隔离级别、传播行为)来进行事务的管理,在管理的过程中事务可能产生了保存点或事务是新的事务等情况,那么这些信息都会记录在TransactionStatus的对象中。

TransactionStatus 接口中定义的主要方法

public  interface TransactionStatus{   boolean isCompleted();                 //事务是否已经完成   boolean isNewTransaction();            //是否是一个新的事务   boolean hasSavepoint();                //是否有保存点   void setRollbackOnly();                //把事务设置成rollback_only   boolean isRollbackOnly();              //事务是否被设置成rollback_only}

通过这些方法可以获取到事务相应的状态。


Spring事务管理

Spring支持两种事务管理方式,编程式和使用XML配置声明式事务
我们需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。编程式在实际中使用很少,这里就不赘述。这里主要介绍XML配置声明式事务。

Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

通常情况下,强烈建议在开发中使用声明式事务,不仅因为其简单,更主要是因为这样使得纯业务代码不被污染,极大方便后期的代码维护。

和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。


1.基于TransactionProxyFactoryBean的声明式事务管理

我们假设一个转账业务,accountService中的transfer方法就是转账的方法。

public class AccountService{    @Autowired    private AccountDao accountDao;    //out为转出帐号 , in为转入帐号 , money为金额    public void transfer(String out,String in,Double money){`       account.outMoney(out,money);   //账户A转出钱        int i = 1/0;                   //抛出一个异常        account.inMoney(in,money);     //账户B收入钱    }}

声明式事务(代理)
applicationContext1.xml配置

    <!-- 配置事务管理 -->    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource"></property>    </bean>    <!-- 装配一个事务代理工厂bean:  TransactionProxyFactoryBean -->    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">        <!-- 配置目标对象 -->        <property name="target" ref="accountService"></property>        <!-- 注入事务管理器 -->        <property name="transactionManager" ref="transactionManager"/>        <!-- 注入事务的属性 -->        <property name="transactionAttributes">            <props>                <!--                     * PROPAGATION :事务的传播行为                    * ISOLATION  :事务的隔离级别                    * readOnly   :只读(不允许进行修改,插入,删除)                    * -Exception :发生哪些异常回滚事务                    * +Exception :发生哪些异常事务不会滚。                 -->                 <prop key="transfer">PROPAGATION_REQUIRED</prop>            </props>        </property>    </bean>

TEST

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext1.xml")public class test{    @Autowired    private AccountService accountService;    @Test    public void demo{        accountService.transfer("aaa","bbb",200d);    }}

这个方式并不经常使用,因为我们要为每一个进行事务管理的类添加一个TransactionProxyFactoryBean,这样后期就会很麻烦。


基于Aspectj的XML的声明式事物管理

applicationContext2.xml配置

  <!-- 配置事务管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    <property name="dataSource" ref="dataSource"></property>  </bean>  <!-- 配置事务的通知 -->  <tx:advice id="txAdvice" transaction-manager="transactionManager">    <tx:attributes>      <tx:method name="transfer" propagation="REQUIRED"/>    </tx:attributes>  </tx:advice>  <!-- 配置切面 -->  <aop:config>    <!-- 配置切入点 -->    <aop:pointcut expression="execution(* com.demo3.AccountService.*(..))" id="pointcut1"/>    <!-- 配置切面 -->    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>  </aop:config>

TEST

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext2.xml")public class test{    @Autowired    private AccountService accountService;    @Test    public void demo{        accountService.transfer("aaa","bbb",200d);    }}

基于注解的方式@Transactional
applicationContext3.xml配置,打开注解事务就行了。

  <!-- 配置事务管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    <property name="dataSource" ref="dataSource"></property>  </bean>  <!-- 开启注解事务 -->  <tx:annotation-driven transaction-manager="transactionManager"/>

然后你需要在什么类上加事务,直接使用注解就行了,注解后面也可以加各种属性

/**propagation     :事务的传播行为*islation        :事务的隔离级别   *readonly        :只读   *rollbackFor     :发生哪些异常回滚*noRollbackFor   :发生哪些不回滚*/@Transactional(propagation=Propagation.REQUIRED,islation=Islation.DEFAULT,readonly=false)public class AccountService{    @Autowired    private AccountDao accountDao;    //out为转出帐号 , in为转入帐号 , money为金额    public void transfer(String out,String in,Double money){`       account.outMoney(out,money);   //账户A转出钱        int i = 1/0;                   //抛出一个异常        account.inMoney(in,money);     //账户B收入钱    }}
原创粉丝点击