Spring事务管理

一、基础知识

1、Spring中的事务分为物理事务和逻辑事务

         物理事务:就是底层数据库提供的事务支持,如JDBC或JTA提供的事务;

         逻辑事务:是Spring管理的事务,不同于物理事务,逻辑事务提供更丰富的控制,而且如果想得到Spring事务管理的好处,必须使用逻辑事务,因此在Spring中如果没特别强调一般就是逻辑事务;

2、@Transactional可指定的事务属性

   @isolation:用于指定事务的隔离级别。默认为底层事务的隔离级别

   @noRollbackFor:指定遇到特定异常时不回滚事务

   @noRollbackForClassName:指定遇到特定的多个异常时不回滚事务

   @propagation:指定事务传播行为

   @readOnly:指定事务是否可读

   @rollbackFor:指定遇到特定异常时回滚事务

   @rollbackForClassName:指定遇到特定的多个异常时回滚事务

   @timeout:指定事务的超长时长。

3、属性参数的含义

        事务隔离级别:用来解决并发事务时出现的问题,其使用TransactionDefinition中的静态变量来指定:

  • ISOLATION_DEFAULT:默认隔离级别,即使用底层数据库默认的隔离级别;
  • ISOLATION_READ_UNCOMMITTED:未提交读;
  • ISOLATION_READ_COMMITTED:提交读,一般情况下我们使用这个;
  • ISOLATION_REPEATABLE_READ:可重复读;
  • ISOLATION_SERIALIZABLE:序列化。

  事务传播行为:Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的,Spring共支持7种传播行为:

  • PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价PROPAGATION_REQUIRED。

二、注解@Transactional用法

      1、在配置文件的头部引入<tx>和<aop>命名空间(以spring-mybatis为例)

 <beans
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="                                          
 http://www.springframework.org/schema/tx                       
 http://www.springframework.org/schema/tx/spring-tx-4.0.xsd                   
 http://www.springframework.org/schema/aop        
 http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

//同时,加入事务配置并开启该事务:
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
</bean>
//记得一定要开启
<tx:annotation-driven proxy-target-class="false" transaction-manager="transactionManager"/>

     2、在需要进行事务处理的方法或者类头上加上

  @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.DEFAULT,rollbackFor = Exception.class)

  注:被申明为事务的方法一定要抛异常,且该异常不能被try{}cathch{}捕获

 

三、注意要点

  • 一个类的内部,方法A调用方法B。在方法B上申明事务而A没有,则方法B的事务不起作用。如果在A上申明而B上没有,则方法B会自动参与该事务。(重要)
  • 在类上申明@Tranactional,相当于在所有的方法上申明@Tranactional。如果不涉及多表的关联操作问题,一般不需要声明。
  • try{}catch{}和rollbackFor是矛盾的(个人理解)。要想实现事务的回滚,必须有Exception产生,如果Exception被捕获,那么注解@Tranactional申明就不起作用。从被调用处到调用处,需要向上抛Exception,直到其被上层捕获。
  • 对于业务逻辑复杂的可根据注解+事务编程来实现。
  • 编程式事务的实现:
    Connection conn = null;  
    UserTransaction tx = null;  
    try {  
        tx = getUserTransaction();                       //1.获取事务  
        tx.begin();                                    //2.开启JTA事务  
        conn = getDataSource().getConnection();           //3.获取JDBC  
        //4.声明SQL  
        String sql = "select * from INFORMATION_SCHEMA.SYSTEM_TABLES";  
        PreparedStatement pstmt = conn.prepareStatement(sql);//5.预编译SQL  
        ResultSet rs = pstmt.executeQuery();               //6.执行SQL  
        process(rs);                                   //7.处理结果集  
        closeResultSet(rs);                             //8.释放结果集  
        tx.commit();                                  //7.提交事务  
    } catch (Exception e) {  
        tx.rollback();                                 //8.回滚事务  
        throw e;  
    } finally {  
       conn.close();                                //关闭连接  
    }  

  详细: http://blog.csdn.net/jiesa/article/details/53438342

原文地址:https://www.cnblogs.com/george93/p/7505938.html