Spring事务管理

 

Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交。

在没有Spring帮我们管理事务之前,service层的代码:

Connection conn = DriverManager.getConnection();
try {  
    conn.setAutoCommit(false);  //将自动提交设置为false                         
    执行CRUD操作 
    conn.commit();      //当两个操作成功后手动提交  
} catch (Exception e) {  
    conn.rollback();    //一旦其中一个操作出错都将回滚,所有操作都不成功
    e.printStackTrace();  
} finally {
    conn.colse();
}

 

    事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了确保数据的完整性和一致在目前企业级应用开发中,事务管理是必不可少的。

    

 

Spring配置事务管理器

例如我在spring-mybatis中配置的:

<!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" /></bean>

 

配置了事务管理器后,Spring提供了两种事务管理的方式:编程式事务管理和声明式事务管理

 

编程式事务管理

    编程式事务管理我们可以通过PlatformTransactionManager实现来进行事务管理。Spring提供了模板类TransactionTemplate进行事务管理,我们需要在配置文件中配置

 <!--配置事务管理的模板-->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
        <!--定义事务隔离级别,-1表示使用数据库默认级别-->
        <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property>
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>
    </bean>

        测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-test.xml"})
public class TransactionTest{
    @Resource
private TransactionTemplate transactionTemplate;

    @Autowired
    private BaseSevice bs;

    @Test
    public void transTest() {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try{
                   //需要进行事务处理的方法
                } catch (Exception e){
                    status.setRollbackOnly();
                    e.printStackTrace();
                }
           }
        });
    }
}

 

声明式事务管理

 

     声明式事务管理有两种常用的方式,一种是基于tx和aop命名空间的xml配置文件,一种是基于@Transactional注解,随着Spring和Java的版本越来越高,大家越趋向于使用注解的方式。
    1.基于tx和aop命名空间的xml配置文件 
    配置文件:

 <tx:advice id="advice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="insert" propagation="REQUIRED" read-only="false"  rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="pointCut" expression="execution (* com.gray.service.*.*(..))"/>
        <aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
    </aop:config>

 

      2.基于@Transactional注解 
    这种方式最简单,也是最为常用的,只需要在配置文件中开启对注解事务管理的支持。

<!-- 声明式事务管理 配置事物的注解方式注入-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    然后在需要事务管理的地方加上@Transactional注解。

    使用@Transactional注解管理事务分两步。第一步开启事务管理,可以在xml中配置,也可以通过@EnableTransactionManagement注解开启;第二步将@Transactional注解添加到方法上,设置属性。   

 name 当在配置文件有多个TransactionManager,可以指定该属性指定选择哪个事务管理器

 propagation 事务的传播行为,默认为REQUIRED

 isolation 事务的隔离级别,默认DEFAULT

 timeout 事务的超时时间,默认-1.如果超过该时间限制事务还没完成,则自动回滚事务

 read-only 指定事务是否为只读事务,默认为false;为了忽略那些不需要事务的方法,比如读取数据,可以设置read-only为true

 rollback-for 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间通过逗号分隔

 no-rollback-for 抛出no-rollback-for指定的异常类型,不回滚事务

除此之外@Transactional也可以添加到类级别上,表示所有该类的公共方法都配置相同的事务属性信息。方法级别的配置会覆盖类级别的相关配置信息

Spring事务传播属性(Propagation):

  • REQUIRED(默认属性)

如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。  

  • MANDATORY 

支持当前事务,如果当前没有事务,就抛出异常。 

  • NEVER 

以非事务方式执行,如果当前存在事务,则抛出异常。 

  • NOT_SUPPORTED 

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

  • REQUIRES_NEW 

新建事务,如果当前存在事务,把当前事务挂起。 

  • SUPPORTS 

支持当前事务,如果当前没有事务,就以非事务方式执行。 

  • NESTED 

新建事务,支持当前事,与当前事务同步提交或回滚。 

PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:
它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA 事务管理器的支持。 使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。 

事务隔离级别(Isolation Level):

事务并发引起的三种情况:

  • Dirty Reads 脏读 

一个事务正在对数据进行更新操作,但是更新还未提交,另一个事务这时也来操作这组数据,并且读取了前一个事务还未提交的数据,而前一个事务如果操作失败进行了回滚,后一个事务读取的就是错误数据,这样就造成了脏读。

  •  Non-Repeatable Reads 不可重复读 

一个事务多次读取同一数据,在该事务还未结束时,另一个事务也对该数据进行了操作,而且在第一个事务两次次读取之间,第二个事务对数据进行了更新,那么第一个事务前后两次读取到的数据是不同的,这样就造成了不可重复读。

  • Phantom Reads 幻像读 

第一个数据正在查询符合某一条件的数据,这时,另一个事务又插入了一条符合条件的数据,第一个事务在第二次查询符合同一条件的数据时,发现多了一条前一次查询时没有的数据,仿佛幻觉一样,这就是幻像读。
非重复度和幻像读的区别:
非重复读是指同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。

幻像读是指同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。

表面上看,区别就在于非重复读能看见其他事务提交的修改和删除,而幻像能看见其他事务提交的插入。 

2.隔离级别:

  • DEFAULT (默认) 

这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。

  • READ_UNCOMMITTED (读未提交) 

这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 

  • READ_COMMITTED (读已提交) 

保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 

  • REPEATABLE_READ (可重复读) 

这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

  • SERIALIZABLE(串行化) 

这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiha_zhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值