数据库事务
参考:
https://blog.csdn.net/weixin_43907800/article/details/104571137
1、事务的四大特性
事务具有4个基本特征,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID
① 原子性(Atomicity)
事务的原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,只允许出现两种状态之一,要么都成功,要么都失败
任何一项操作都会导致整个事务的失败,同时其它已经被执行的操作都将被撤销并回滚,只有所有的操作全部成功,整个事务才算是成功完成
② 一致性(Consistency)
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。
一致性的定义
-
百度百科-一致性
一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。
-
百度百科-事务一致性
一个或多个事务执行后,原来一致的数据和数据库仍然是一致的。它主要涉及事务的原子性。
-
维基百科-一致性(数据库)
一致性是数据库系统的一项要求:任何数据库事务修改数据必须满足定义好的规则,包括数据完整性(约束)、级联回滚、触发器等。
我对一致性的理解
“一致”是指数据库中的数据是正确的,不存在矛盾。事务的一致性是指事务执行前后,数据都是正确的,不存在矛盾。如果执行后数据是矛盾的,事务就会回滚到执行前的状态(执行前是一致的)。
满足一致性的例子
- 学生表中的学号是唯一的。
- 账户的余额减少了,账单中要有对应的扣款记录,且减少的金额和账单的扣款金额一致。
- 一篇文章浏览量为100次,则浏览记录表有该文章的100条浏览记录。
- 发布文章的用户ID是100,则用户表中存在ID为100的用户。
不满足一致性的例子
- 学生表中有重复的学号。
- 转账成功了,但是付款的人余额没扣,或者收款的人余额没有增加。
- 付款多次,只扣款1次(或者付款1次,扣款多次)。
- 发布文章的用户ID是100,但用户表中没有ID=100的用户。
- 文章的发布时间是空的。
- 用户的年龄是负数。
- 用户的年龄是字母。
③ 隔离性(Isolation)
事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。
一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的。
④ 持久性(Duration)
事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。
在事物进行过程中,未结束之前,DML语句是不会更改底层数据,只是将历史操作记录一下,在内存中完成记录。只有在事物结束的时候,而且是成功的结束的时候,才会修改底层硬盘文件中的数据。
只有保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障
2、并发事务会产生哪些问题?
- 脏读(Dirty read): 一个事务读到另一个事务未提交的更新数据。当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
- 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。
- 不可重复读(Unrepeatable read): 一个事务两次读同一行数据,可是这两次读到的数据不一样。指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
- 幻读(Phantom read): 一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。幻读与不可重复读类似,它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读和幻读有什么区别?
- 不可重复读的重点是内容修改或者记录减少比如多次读取一条记录发现其中某些记录的值被修改;
- 幻读的重点在于记录新增比如多次执行同一条查询语句(DQL)时,发现查到的记录增加了。
3、事务的隔离级别详解
事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。
一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的。
不同的隔离级别可以解决不同的问题,SQL的标准事务隔离级别包括:
- 读未提交(READ-UNCOMMITTED): 一个事务还没有提交时,它做的变更就能被别的事务看到。最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- 读提交(READ-COMMITTED): 一个事物提交之后,它做的变更才会被其他事务看到。允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- 可重复读(REPEATABLE-READ): 一个事物执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的,未提交变更对其他事务也是不可见的。 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
MySql的默认隔离级别就是REPEATABLE-READ。 - 串行化(SERIALIZABLE): 对于同一行记录,写会加“写锁”,读会加“读锁”,当出现锁冲突时,后访问的事务需要等前一个事务执行完成,才能继续执行。最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
在@Transactional中存在isolation 属性
isolation :事务的隔离级别,默认值为 Isolation.DEFAULT。
Isolation.DEFAULT:使用底层数据库默认的隔离级别。
Isolation.READ_UNCOMMITTED - 读未提交
Isolation.READ_COMMITTED - 读已提交
Isolation.REPEATABLE_READ - 可重复读
Isolation.SERIALIZABLE - 串行化