spring 事务传播机制和隔离级别

发布于 2019-10-13

spring 事务传播机制和隔离级别

事务最重要的两个特性,是事务的传播级别和数据隔离级别。传播级别定义的是事务的控制范围,事务隔离级别定义的是事务在数据库读写方面的控制范围。

1.传播机制

事务的传播性一般在事务嵌套时候使用,比如在事务A里面调用了另外一个使用事务的方法,那么这俩个事务是各自作为独立的事务执行提交,还是内层的事务合并到外层的事务一块提交呢,这就是事务传播性要确定的问题。下面一一介绍比较常用的事务传播机制。

1、PROPAGATION_REQUIRED
若当前存在事务,则加入该事务,若不存在事务,则新建一个事务。

class C1(){
    @Transactional(propagation = Propagation.REQUIRED)
    function A(){
        C2.B();
    }
}
 
class C2(){
    @Transactional(propagation = Propagation.REQUIRED)
    function B(){
        do something;
    }
}

若B方法抛出异常,A方法进行捕获,A会抛出异常,因为C2标志回滚,C1标志提交,产生冲突。
若B方法抛出异常,B方法内部捕获,A、B都不会回滚。
若A或B抛出异常,但没有捕获,则A、B都回滚。
A、B可操作同一条记录,因为处于同一个事务中。

2、PAOPAGATION_REQUIRE_NEW
若当前没有事务,则新建一个事务。若当前存在事务,则新建一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交。

class C1(){
    @Transactional(propagation = Propagation.REQUIRED)
    function A(){
        C2.B();
    }
}
 
class C2(){
    @Transactional(propagation = Propagation.REQUIRE_NEW)
    function B(){
        do something;
    }
}

若B方法抛出异常,A方法进行捕获,B方法回滚,A方法不受B异常影响。
若B方法抛出异常,B方法内部捕获,A、B都不会回滚。
若A方法抛出异常,不会影响B正常执行。
若B方法抛出异常,A、B方法都没有处理,则A、B都会回滚。
A、B不可操作同一条记录,因为处于不同事务中,会产生死锁。

3、PROPAGATION_NESTED
如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务,则新建一个事务,类似于REQUIRE_NEW。

class C1(){
    @Transactional(propagation = Propagation.REQUIRED)
    function A(){
        C2.B();
    }
}
 
class C2(){
    @Transactional(propagation = Propagation.NESTED)
    function B(){
        do something;
    }
}

若B方法抛出异常,A方法进行捕获,B方法回滚,A方法正常执行。
若A或者B抛出异常,不做任何处理的话,A、B都要回滚。
A、B可操作同一条记录,因为处于同一个事务中。

4、PROPAGATION_SUPPORTS
支持当前事务,若当前不存在事务,以非事务的方式执行。

5、PROPAGATION_NOT_SUPPORTED
以非事务的方式执行,若当前存在事务,则把当前事务挂起。

class C1(){
    @Transactional(propagation = Propagation.REQUIRED)
    function A(){
        C2.B();
    }
}
 
class C2(){
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    function B(){
        do something;
    }
}

A、B不可操作同一条记录,因为A是事务执行,B在A尚未提交前再操作同一条记录,会产生死锁。

6、PROPAGATION_MANDATORY
强制事务执行,若当前不存在事务,则抛出异常

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

2.隔离级别

隔离级别是指若干个并发的事务之间的隔离程度,与我们开发时候主要相关的场景包括:脏读取、重复读、幻读。

1、读未提交(READ_UNCOMMITED):允许读取还未提交的改变了的数据。可能导致脏读、幻读、不可重复读。
2、读已提交(READ_COMMITED):允许在并发事务已经提交后读取。可防止脏读,但幻读、不可重复读仍可能发生。
3、可重复读(REPEATABLE_READ):对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏读、不可重复读。但幻读仍可能发生。
4、可串行化(SERIALIZABLE):事务顺序执行,可避免脏读、不可重复读、幻读,但效率最差。因为A事务执行时,要完全锁住在事务中涉及的数据表。

3.异常捕获

spring中可以指定当方法执行并抛出异常的时候,哪些异常回滚事务,哪些异常不回滚事务。默认情况下,只在方法抛出运行时异常的时候才回滚(runtime exception)。而在出现受阻异常(checked exception)时不回滚事务。当然可以采用申明的方式指定哪些受阻异常像运行时异常那样指定事务回滚。

// 所有异常都会回滚
@Transactional(rollbackFor = Exception.class)

4.配置方法

XML配置:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
     <tx:attributes>
          <tx:method name="query*" read-only="true" propagation="SUPPORTS" />
          <tx:method name="get*" read-only="true" propagation="SUPPORTS" />
          <tx:method name="insert*" propagation="REQUIRED" />
          <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
          <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
          <tx:method name="remove*" propagation="REQUIRED" />
          <tx:method name="delete*"  propagation="REQUIRED" />
     </tx:attributes>
</tx:advice>

由于没有给method配置isolation属性,所以默认是isolation=‘DEFAULT’,也就是使用后端数据库默认的隔离级别。

注解配置:
传播机制:@Transactional(propagation=Propagation.REQUIRED)
隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED)

喜欢 0
奋楫笃行,臻于至善!

相关文章

使用 Mycat 中间件搭建 MySQL 高可用实现分库分表及读写分离

Mycat 是一款基于阿里开源产品Cobar而研发的开源数据库分库分表中间件(基于Java语言开发),可以用来方便地搭建面向企业应用开发的大数据库集群,支持事务、ACID等特性,其核心是基于代理方案实...
阅读全文

通用架构模式和通用架构服务

架构模式是在给定上下文的软件架构中,针对常发生问题的一种通用、复用的解决方案。架构模式类似于软件设计模式,但是范畴更广。一个好的软件产品往往需要有良好的架构思想和架构服务来支撑整个软件的生命周期,本文...
阅读全文

Java 的可重入锁和不可重入锁

可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞。Java中Reentra...
阅读全文

Redis 的两种持久化方式及使用场景分析

Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,利用持久化文件实现数据恢...
阅读全文

redis 高可用主从,哨兵,集群解决方案

Redis因为其高性能和易用性在我们后端的服务中发挥了巨大的作用,并且很多重要功能的实现都会依赖redis。除了常用的缓存,还有队列,发布订阅等重要用处。所以redis的服务高可用就显得尤为关键。这里...
阅读全文

Redis 缓存穿透、缓存击穿、缓存雪崩的区别及解决方案

Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很...
阅读全文

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注