关于MYSQL数据库中的的四个事务等级的实例

数据库中有四种事务等级:

1、Read Uncommitted(读取未提交内容);
2、Read Committed(读取提交内容);
3、Repeatable Read(可重读);
4、Serializable(可串行化);

这四种级别我第一次接触的时候,前面两种还好理解,越往后面的越无法理解,我相信初学者也会遇到类似的情况。最好的方式还是通过简单的实验例子逐个进行说明和区分,比起单纯的文字理论学习起来更有效。其实这几种事务等级,主要还是对并发的程序产生影响,如果程序一直是单线程连接数据库执行操作,那就不会存在问题,也不需要事务等级了。

下面简述一下这四种事务级别:

第一级别、Read Uncommitted(读取未提交内容):

所有事务都可以看到其他未提交事务的执行结果。

例如:
1、开启事务A,此时在事务A中查询a=20;
2、开启事务B,事务B把a值改为10,未提交;
3、事务A中查看a值发现等于10;
4、事务B把a值改为30,未提交;
5、事务A中查看a值发现等于30
……
 

就是说,事务A开启后,事务B只要修改了某个值,就算事务B没提交,A中看到的数值都会改变。这就是传说中的“脏读(dirty read)”。试想一下,如果一个事务没有提交,那么其中改变的一些数值可能只是操作过程的一个中间值,那么另一个事务读取这样一个中间值的意义何在呢?

第二级别、Read committed(读取提交内容):
一个事务只能看见已经提交事务所做的改变,这个事务等级解决了脏读的问题,与第一个事务等级同样的例子。
例如:
1、开启事务A,此时在事务A中查询a=20;
2、开启事务B,事务B把a值改为10,未提交;
3、事务A中查看a值仍然不变为20;
4、事务B把a值改为30,未提交;
5、事务A中查看a值仍然不变为20;
……

就是说,事务A开启后,事务B修改了某个值,如果事务B没提交,那么A中看到的数值是不会改变的,这就解决了“脏读”的问题。然而这个事务等级仍然会存在“不可重复读”的问题。
例如:
1、开启事务A,此时在事务A中查询a=20;
2、开启事务B,事务B把a值改为10,提交;
3、事务A中查看a值变为10;
4、事务B把a值改为30,提交;
5、事务A中查看a值变为30;
……

就是说,在同一个事务中进行多次查询,由于其他事务改变了某些值,会导致前后两次查询的值不一样,这种情况就是“不可重复读”。事务执行过程中读取另一个事务已提交的结果是有一定道理,因此也有不少数据库引擎默认的事务等级是这一级。但是如果不能管理可重复读这种层面的并发,就类似于所有课本里用银行账户讲解锁的场景一样。依靠应用程序去管理这种层面的并发,应用程序很难管得那么细,如果应用程序给一个很大范围的数据加上锁,对并发效率影响肯定很大。

扫描二维码关注公众号,回复: 10470745 查看本文章

第三级别、Repeatable Read(可重读):
确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。
例如:
1、开启事务A,此时在事务A中查询a=20;
2、开启事务B,事务B把a值改为10,提交;
3、事务A中查看a值仍然不变为20;
4、事务B把a值改为30,提交;
5、事务A中查看a值仍然不变为20;
……

就是说,在同一个事务中进行多次查询,即使其他事务改变了某些值,也不会影响前后两次查询得到的值,正如上面例子,事务A开始的时候a=20,那无论其他事务怎么改这个值,甚至删掉这个值,事务A中查询a都是等于20,这种情况就是“可重复读”。然而这种事务等级依然存在“幻读”的问题
例如:
假设id是一个表的主键
1、开启事务A,此时在事务A中查询发现表中不存在id=10的记录;
2、开启事务B,事务B插入一条id=10的记录,提交;
3、事务A中查看表会发现存在id=10的这条记录。
……

就是说在一个事务中查询某一个范围的数据,后来别的事务在这个范围内插入一行数据。前一个事务再次查询会发现多了一个记录,这就是“幻读”。不过在mysql上实践时,我没有看到这个现象,因为mysql的MVCC(多版本并发控制)解决了这个问题。但是其实还存在一个小问题,就是mysql虽然在第3步中,事务A不会查询到id=10的记录,但是当你插入一条id=10的记录时会报键值重复。不过这种情况的影响相对不大,大不了遇到插入或删除错误的时候进行异常处理,换个id插入或者直接返回错误就好了,对数据的影响不是很严重,所以mysql的默认事务等级是这一级。

第四级别、Serializable(可串行化):
强制事务排序,使之不可能相互冲突。
在这种情况下,当一个事务读取某一范围的数据时,会为这个范围的数据加上行锁,别的事务要对这个范围的数据进行修改或者插入之类的操作,只能等待锁的释放,因此会一直被阻塞。
例如:
1、开启事务A,事务A查询某个表t;
2、开启事务B,事务B准备往表t中插入某个记录,此时会阻塞;
3、事务A提交后,事务B的插入操作才能执行;
……

在这种事务级别下,可以避免“幻读”的问题,不过由于所有事务的读写都需要加上锁,因此效率会下降很多。这个级别让不同事务在处理同一个数据范围时保持串行,彻底保证不会产生并发导致的问题,但这样的效率下降太多,根据不同的场景,某些应用不需要担心幻读的问题,那就没必要设置为可串行化的事务级别。

发布了39 篇原创文章 · 获赞 5 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sadoshi/article/details/78101462