前言:
- 最近在学习Spring原理及底层相关知识,必然会学到Spring中的一大特性:声明式事务管理。 故开始了解数据库事务到底是什么,可能之前只知道一个bo方法就是一个事务,但从来连最基本的原理都没深究过。
- 该篇文章为数据库事务起始文章,大概讲解一下数据库事务基本内容,包括事务特性,事务隐患,隔离级别,以及代码层面的事务传播。
- 其次会另开几篇文章,记录网上搜寻到的关于mysql实现不同隔离级别的方式。其中可能会说到各种锁及innodb引擎,及其中MVCC多版本控制实现原理。
- Spring声明式事务在Spring文集中展示,此处就不再罗列。
文章目录
一、事务四大特性ACID
1.1 原子性(Atomicity)
- 定义:事务包含的所有操作要么全部成功,要么全部失败回滚;成功必须要完全应用到数据库,失败则不能对数据库产生影响。
1.2 一致性(Consistency)
- 定义:事务执行前和执行后必须处于一致性状态.例如:转账事务执行前后,两账户余额的总和不变。
- 该例子网上博客列举最多,个人觉得很片面。首先会想这不是原子性实现的东西嘛。https://www.zhihu.com/question/30272728,可参考该博文解惑。
1.3 隔离性(Isolation)
- 定义:多个并发的事务之间要相互隔离。
- 俩事务同时查询和更新同一条数据怎么办。不同的数据库都有各自的解决方式,数据库层面就已解决。但开发人员尽量清楚了解内部原理更好。
1.4 持久性(Durability)
- 定义:事务一旦提交,对数据库的改变是永久性的。
- 不同的存储技术基本都有持久化概念,也就是如何将数据保存到硬盘。
四大特性,详见:https://www.jianshu.com/p/58f0109ff89e
二、事务的安全隐患
2.1 脏读
- 定义:一个事务读到另外一个事务还未提交(可能被回滚)的脏数据。
2.2 不可重复读
- 定义:一个事务执行期间另一事务提交修改,导致第一个事务前后两次查询结果不一致。
2.3 幻读
- 定义: 一个事务执行期间另一事务提交添加数据,导致第一个事务前后两次查询结果到的数据条数不同。
- 幻读和不可重复读,区别在于不可重复读为更新,幻读为插入。
2.4 脏写
- 定义:一个事务更新了另一个事务已经更新但是还未提交的数据。
- 所有隔离级别都不允许脏写。
三、事务的隔离级别
3.1 ISOLATION_READ_UNCOMMITTED: 读未提交
- 事务中的修改,即使没有提交,其他事务也可以看得到.会导致脏读,不可重复读,幻读.
3.2 ISOLATION_READ_COMMITTED: 读已提交
- Oracle数据库默认隔离级别
- 一个事务不会读到其它并行事务已修改但未提交的数据.避免了脏读,但会导致不可重复读,幻读.
3.3 ISOLATION_REPEATABLE_READ: 可重复读
- Mysql数据库默认的隔离级别,且mvcc解决了幻读
- 一个事务不会读到其它并行事务已修改且已提交的数据,(只有当该事务提交之后才会看到其他事务提交的修改).避免了脏读,不可重复读,但会导致幻读
3.4 ISOLATION_SERIALIZABLE: 串行化
- 事务串行执行,一个时刻只能有一个事务被执行.避免了脏读,不可重复读,幻读。
3.5 实例
可以通过下面的例子理解事务的隔离级别:
事务A | 事务B |
---|---|
启动事务 查询得到原始值origin=1 | |
启动事务 | |
查询得到值1 | |
将1改成2 | |
查询得到值value1 | |
提交事务B | |
查询得到值value2 | |
提交事务A | |
查询得到值value3 |
对不同的事务隔离级别,事务A三次查询结果分别如下:
事务隔离级别 | 原始值origin | value1 | value2 | value3 |
---|---|---|---|---|
ISOLATION_READ_UNCOMMITTED | 1 | 2(脏读) | 2 | 2 |
ISOLATION_READ_COMMITTED | 1 | 1 | 2(不可重复读) | 2 |
ISOLATION_REPEATABLE_READ | 1 | 1 | 1 | 2 |
ISOLATION_SERIALIZABLE | 1 | 1 | 1 | 1 |