- 事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)
- 一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成
- 事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同;
- 原子性(A):事务的最小单位,不可再分。
- 一致性(C):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败。
- 隔离性(I) :事务A和事务B之间具备隔离性。
- 持久性(D):是事务的保证,事务终结的标致(内存中的数据持久到硬盘文件中)。
指 一个事务读取了另外一个事务未提交的数据。此时如果回滚,前者两次读取同一个SQL获取的数据是不一样的。
【1】A事务首次查询到id=1 的数据为2,A事务未结束, B事务 将id=1的数据修改为3,B事务并未提交。
【2】A事务再次查询id=1的数据,发现数据发生了变化。
在一个事务的两次查询中数据不一致。例如 有一个事务查询了几列数据,而另一个事务却在此时**插入(insert)**了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是他之前所没有的。
在一个事务中使用相同的 SQL 两次读取,第二次读取到了其他事务新插入的行。不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。
指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改(update) 并事务提交,那么第一个事务在同一个事务中两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 READ-UNCOMMITTED |
√ | √ | √ |
| 读已提交 READ-COMMITTED |
× | √ | √ |
| 可重复读 REPEATABLE-READ |
× | × | √ |
| 串行化 SERIALIZABLE |
× | × | × |
| 读未提交(Read Uncommitted) | 最低的隔离级别,会读取到其他事务还未提交的内容,存在脏读。 |
|---|---|
| 读已提交(Read Committed) | 读取到的内容都是已经提交的,可以解决脏读,但是存在不可重复读。 |
| 可重复读(Repeatable Read) | 在一个事务中多次读取时看到相同的内容,可以解决不可重复读,但是存在幻读。但是在 InnoDB 中不存在幻读问题,对于快照读,InnoDB 使用 MVCC 解决幻读,对于当前读,InnoDB 通过 gap locks 或 next-key locks 解决幻读。 |
| 串行化(Serializable) | 最高的隔离级别,串行的执行事务,没有并发事务问题。 |
- 演示隔离级别 准备条件
创建一张金额表:
create table account
(
id bigint auto_increment
primary key,
amount bigint null,
name varchar(128) null
);预先写入一条数据;
| id | amount | name |
|---|---|---|
| 1 | 1100 | A |
上面同样的操作 做一个 insert 语句,读了别人 未提交的 数据,多读,别人一回滚 就发现又变少了。
很好理解,不可重复读 意思是前后 两次读到的不一致。肯定不一致呀。
都会造成脏读,更何况 不可重复读, console 1 只要修改了,console 就会查询到。怎么能做到重复读 ?
在当前事务 更新并 查询 更新后的数据,发现age 变化了!
但此时 事务还没有提交!
在console 无论重新开启多少次 事务查询,发现还是之前的数据。
发现 变化了,证明 在 事务一中读取了 事务2 已提交的更新。
根据 3.2.1 可以得知 ,console 在 一个事务中 可以 读到 console 1 中已提交的所有变动。
那么在console 中 第一次查询 id >1 的记录有2条,然后再 console 1中新插入一条后并提交事务
再次在console 中查询 id > 1 的记录 就有3条,因此 造成了 幻读。
按照3.3.2.1 正常处理的流程,在 console 1 中新增一条数据后并提交
insert student value (12345,'aaa',2);在console 原事务中查询 是看不到新增数据的。
但是此时 做update 操作
update student set age =10000 where id=12345
id=12345,为新增数据
然后再次执行查询就会发现 新增的数据 出现了,因此在同一个事务中可重复读 的事务隔离级别发生了幻读。
因为
而对于 update 、 insert、delete 都是采用当前读的模式。
在执行这几个操作时会读取最新的版本号记录,写操作后把版本号改为了当前事务的版本号,所以即使是别的事务提交的数据也可以查询到。
1,Record Lock:单个行记录上的锁。
2,Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。
3,Next-Key Lock:1+2,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题
Innodb 通过Buffer Pool ,Redo Log Buffer , Redo Log,Undo Log 来实现事务,以一个update 语句为例子:
- Innodb 在接收到一个update 语句的时候,会先根据条件找到数据所在的页,并将页缓存到Buffer Pool 中
- 执行update 语句的时候,修改Buffer Pool 中的数据,也就是内存中的数据。
- 针对update 语句在操作bufferpoll时,同时生产一个redo log 对象,并存入Redo Log buffer 中
- 针对update 语句生产undo log 日志,用于事务回滚。
- 如果事务提交之前,那么咋把Redolog 对象对象进行持久化,写入到redo 日志文件中(磁盘中);
- 写binlog
- 定期将Buffer Pool中 脏页刷到磁盘中。(时机:【1】1s一次,可能丢事务【2】事务提交时【3】复合条件)
- 如果事务回滚,利用undo log 日志进行回滚。
[
](https://www.jianshu.com/p/8845ddca3b23)
MVCC 快照读 引发 幻读原因
https://www.jianshu.com/p/bdcf46cdef7c
https://zhuanlan.zhihu.com/p/48269420
https://www.jianshu.com/p/8845ddca3b23


























