Spring事务的隔离级别和传播机制

Spring事务的隔离级别和传播机制

 

一、什么事务

事务就是一系列数据库操作的序列,这个序列是一个不可分割的逻辑单元,在其中的操作要么全部完成,要么全部无法完成。一个完整的事务必须满足

(ACID),所谓的ACID指的是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

原子性:在一个事务中的操作都是一个逻辑的单元,在执行事务序列时,这些操作要么全部成功,要么全部失败。

一致性:对于事务操作,其始终能够保证在事务操作成功或者失败回滚时能够达到一种一致的状态。

隔离性:各个事务之间的执行是相互不影响。

持久性:事务的持久性指的是事务一旦执行成功,那么其所做的修改将永久的保存在数据库中,此时即使数据库崩溃,修改的数据也不会丢失。

二、隔离级别问题

脏读

脏读表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录A,此时该事务还未提交,然后另一个事务尝试读取记录会成功读取到记录A的。

幻读

幻读就是指A事务对所有记录进行修改,尚未提交,此时B事务创建了一条新记录,A、B都提交。A查看所有数据,发现有一条数据没有被修改,因新增的,就想看到了幻象一样。

不可重复读

不可重复度指A事务对一条记录进行修改,尚未提交,B事务第一次查询该记录,看到的是修改之后的结果,此时A发生回滚,B事务又一次查询该记是回滚后的结果。同一个事务内,B两次查询结果不一致。

 

三、事务隔离级别

事务隔离级别就是为了解决脏读、幻读、不可重复读着这几个问题而产生的,但是事务隔离级别不同,产生的问题也不同,因此很多时候必须在并发性一个权衡,所以设立了几种事务隔离级别,以便让不同的项目可以根据自己项目的并发情况选择合适的事务隔离级别。事务隔离级别默认又四种,不过种:

1. DEFAULT:默认隔离级别,每种数据库支持的事务隔离级别不一样,Oracle默认(读已提交) Mysql默认(可重复读)。

2. READ_UNCOMMITTED:读未提交,即能够读取到没有被提交的数据,这是隔离性最低的一种隔离级别,无法解决脏读、不可重复读、幻读问题

3. READ_COMMITED:读已提交,即能够读到那些已经提交的数据,能够防止脏读,避免不了幻读和不可重复读。

4. REPEATABLE_READ:可重复读,解决脏读和不可重复读的问题,但是其无法解决幻读。

5. SERLALIZABLE:串行化,提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,故此性能很低

 

四、事务传播机制

1. PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。

2. PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

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

4. PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。

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

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

7. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作

五、事务只读属性

Spring事务只读的含义是指,如果后端数据库发现当前事务为只读事务,那么就会进行一系列的优化措施。它是在后端数据库进行实施的,因此,只有可能启动一个新事务的传播行为(REQUIRED,REQUIRES_NEW,NESTED)的方法来说,才有意义。

 

六、事务超时

有的时候为了系统中关键部分的性能问题,它的事务执行时间应该尽可能的短。因此可以给这些事务设置超时时间,以秒为单位。我们知道事务的发生数据库的表锁或者被数据库优化为行锁,如果允许时间过长,那么这些数据会一直被锁定,影响系统的并发性。因为超时时钟是在事务开始的时候启动,因此只有对于那些有可能启动新事物的传播行为(REQUIRED,REQUIRES_NEW,NESTED)的方法来说,意义。

七、事务回滚规则

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

简单来说 #{} 会在将参数加上引号,例如:

SELECT * FROM user WHERE username=#{username} ;

带上参数后的SQL语句即:

SELECT * FROM user WHERE username="XuLiTong" ;

${}并不会在给参数加上引号,例如:

SELECT * FROM user ORDER BY ${id} DESC LIMIT #{offset},#{limit};

带上参数后的SQL语句为:

SELECT * FROM user ORDER BY id DESC LIMIT 0,10;

可见,mybatis对参数没有进行任何的处理,际应用中,并不提倡使用 ${},因为使用 #{} 写法,除了可以防止sql注入以外,还能在参数里含有单引号的时候自动转义。

原文地址:https://www.cnblogs.com/LPJ-BLOG/p/12371100.html