Spring-声明式事务(一)——隔离属性


## 前言

众所周知,Spring 的事务属性众多,楼主今天将对 Spring 最常用的事务 —— 声明式事务,进行彻底的解释,包括楼主也写了很多的测试例子。代码地址: 使用 tk-mybatis 的 demo 测试了 Spring 的事务

东西很多,楼主分为 3 个部分来写,第一就是隔离属性了,第二是传播属性,第三是其他属性。

隔离属性

事务要解决的是多线程并发修改数据库的问题。Mysql innodb 引擎支持事务。类似 Java 中的各种锁,例如乐观锁(CAS),读写锁,悲观锁。事务也有很多级别。

每个隔离级别要解决的问题都是不同的。

一张表格来看看。

以上是 Spring 事务每个隔离级别能够解决的问题。

再说说脏读,不可重复读,幻读的解释。

脏读场景:
1.事务 A 读取数据
2.事务 B 修改数据(未提交)
3.事务 A 读取数据已和第一次读的不同

不可重复读场景:
1.事务 A 读取数据
2.事务 B 修改数据(提交)
3.事务 A 读取数据已和第一次不同

幻读场景:
1.事务 A 读取数据
2.事务 B 新增数据
3.事务 A 再次读取的数据数量已和第一次的数量不同

注意: 幻读指的是读到的数据的数量,针对插入情况,会产生不一致情况,修改则不会.

再解释一下 4 个隔离级别:

  1. 未提交读:表示另一个事务修改了数据,还没有提交,这个事务就可以读到了。
  2. 已提交读:表示另一个事务修改了数据,同时提交了,这个事务就可以读到了,如果没提交,就读不到。
  3. 可重复读:表示另一个事务即使修改了数据(已提交),这个事务也是看不到的,因此这个事务每次读到的数据都是一样的。这叫可重复读。但
  4. 可串行化:可以想象成 Java 语言的锁。一个个执行。毫无并发性。性能令人发指。

其中关于可重复读需要解释一下在 mysql 场景下的幻读问题,按照标准,可重复读应该会导致幻读,但 mysql 如果在一个事务中,第二次读取的数据使用的是第一次的结果,因此不会产生幻读。

关于默认的级别,很多文章说是 “已提交读”,但经过详细的测试,应该是可重复读。

因此,大部分时候,使用默认的级别,就能得到和串行化相同的目的。而串行的成本则是非常的高昂,类似悲观锁。还有一点,mysql 的事务是借助行锁来实现的。