MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题

事务关键字:begin / commit/ rollback

1、测试四种隔离级别

建立测试表

CREATE TABLE User(
	id int(11) not null primary KEY auto_increment,
	name varchar(20),
	age int DEFAULT 0
)ENGINE = INNODB DEFAULT CHARSET=gb2312;
insert into `user` values (1,'zhangsan',23);
insert into `user` values(2,'lisi',20);

查看隔离级别

select @@tx_isolation;

MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第1张图片
结果可以知道默认的隔离级别是:可重复读

更改隔离级别

其中global是全局会话,session是当前会话

set [global | session] transaction isolation level read uncommitted;
  • Read Uncommited

在这里插入图片描述
再次查看当前的隔离级别:对当前的无效,需要重新打开一个会话
MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第2张图片MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第3张图片
测试场景 :

1、打开两个新的窗口,同时开启事务
2、在第一个窗口先update一个id=1的数据行name改为’huhu’ 且不提交
3、在第二个窗口查看未提交的数据

测试结果

未更改之前
MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第4张图片
更改未提交
MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第5张图片
结论:在READ-UNCOMMITED下第二个会话可以查看到第一个会话的未提交的内容

  • READ COMMITTED(读已提交)

同上更改隔离级别为 READ-COMMITTED;

测试场景
1、打开两个新的窗口,同时开启事务
2、第二个窗口查询当前id =1 的name 值
3、第一个窗口更新 id =1 的name 为 ”zhangsan“
4、第二个窗口再次查看id =1的name值

测试结果
1、在该隔离级别下解决了未提交数据不能查看的问题
在这里插入图片描述
2、在该隔离级别下,如果进行update操作会导致前后查询的结果不一致,即产生脏数据
在这里插入图片描述

  • REPEATABLE READ(可重复读)

同上更改隔离级别为REPEATABLE READ;

测试场景
1、打开两个新的窗口,同时开启事务
2、第二个窗口查询当前id =1 的name 值
3、第一个窗口更新 id =1 的name 为 ”zhangsan“
4、第二个窗口再次查看id =1的name值
5、第二个窗口查看当前uset 表中的所有数据
6、第一个窗口插入一条记录并提交
7、在第二个窗口中再次查看user表的数据

测试结果
1、解决了脏读的问题
MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第6张图片
2、在MySQL的RR级别下也解决了幻读的问题(两次查询的行数不同)
MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第7张图片

  • 可串行化
    测试场景同RR级别一致
    解决了三种可能出现的问题

2、 MySQL的锁机制
1)隔离级别越高,性能越差,这是由于在MySQL中是通过锁机制来解决存在的问题。

2)锁机制:共享锁(读锁 Shared Lock)、排它锁(写锁 Exclusive Lock)、间隙锁(Record Lock)、表锁
按照粒度:行锁(Innodb支持)、表锁

3)串行化的实现
读的时候加共享锁,不能写
写的时候加排他锁,阻塞其它事务的读取和写入

4)读已提交和可重复读

底层采用MVCC(多版本并发控制协议)

5)间隙锁则分为两种:Gap Locks和Next-Key Locks。Gap Locks会锁住两个索引之间的区间,比如select * from User where id>3 and id<5 for update,就会在区间(3,5)之间加上Gap Locks。(解决幻读问题)

6)增删改加排它锁,查询不会加锁
只能通过在select语句后显式加lock in share mode或者for update来加共享锁或者排它锁。

3、 MVCC(多版本并发控制协议)
详细参考:https://blog.csdn.net/w2064004678/article/details/83012387
1)在事务开始的时候创建一致性视图(快照),之后的查询里共用这个一致性视图,后续的事务对数据的更改对当前事务时不可见的。
2)在MySQL的Innodb引擎中,会为每个事务分配一个row trx_id(唯一性,递增性)
在每次事务更新数据的时候,都会生成一个新的数据版本,并且把自己的数据id赋值给当前版本的row trx_id。

MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第8张图片
三个事务更新同一行,就会有三个不同的版本,按照事务的先后执行顺序(快照视图)。
快照遵循的原则:1)自己更新的必须可见 2)版本未提交不可见 3)版本已提交,但是是在创建视图之后提交的也不可见
4)在创建视图之前可见

4、如何实现并发操作?

引用上面的测试表

测试场景
1)两个窗口同时开启事务
2)第一个窗口更新id=1的name值为”huhu_test"未提交
3) 第二个窗口更新id=1的name值为”huhuhuhuhu_test"
4) 查询执行效果
MySQL事务:模拟实现不同隔离级别下产生的一致性相关问题_第9张图片

测试结果分析
1)窗口一可以update成功
2)窗口二提示锁等待超时

这是由于,在执行update操作时,窗口1先获得行锁并锁定数据,窗口二要进行update时,也需要获取行锁,但是由于窗口一占有,只能等待;窗口一一直不提交,就会出现超时异常了(以上的情况是在有索引的情况下进行的)

在没有索引的情况下,需要全表扫描筛选出对应的行并加锁。

你可能感兴趣的:(MySQL)