一共有那几种隔离级别?分别叫什么?不同的隔离级别会有什么的问题?这些网上一搜一大把,我就不在墨迹了!看下面一个表就足够了。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
有时候我自己也总是忘记“不可重复度”,“幻读”之间的区别。所以本文打算主要讲讲到底什么是不可重复读?什么是幻读?
不可重复读
在一次事务中,每次查询到的数据不相同!
假设数据库中有名为person的表数据如下(共一行记录):
id | name |
1 | zhangsan_v1 |
如下所示,打开俩个连接(打开俩个mysql终端或客户端)connection A 和 connection B 。蓝色虚线表示时间轴,connection A 开启一个事务,在执行期间 connection B 执行了一条insert 和 update 语句!
第一次select 查询得到的结果如下:
第二次select 查询得到的结果如下:
可以看到 connection A 在一个事务中同一条查询语句得到不同的结果,产生了不可重复读的问题。
幻读
通俗点说:在同一事务中有些数据在读时候感受不到它们,但在写的时候却能感受到它们的存在!这些数据确是确实存在的,只是读不到而已。有点绕,看demo,就明白了!
假设数据库中有名为person的表数据如下(共俩行记录,id为主键):
id | name |
1 | name1 |
2 | name2 |
开启俩个mysql 连接 connection A 和 connectionB,设置 A 的事务为手动提交,隔离级别为重复读(repeatable read),在第8行第一次select 后 connecton B 执行了insert 占用主键:3,同时修改id = 1的name值从: name1 改为 name1_v2;
第8行第一次select 结果如下:
第12行第二次select 结果如下:
可以看到在第二次select的时候,虽然connecton B 修改了表数据,但是connection A 还是查不到,和第一次select查询到的数据一致的,这就是可重复读。那么幻读是什么呢?注意,重点马上来了,看下面第14行insert 语句的执行结果;
第14行insert 语句执行结果:可以看到居然主键冲突了,可明明第二次select的时候没有查到id=3的数据啊,为啥insert的时候报主键冲突呢?其实这就是幻读。你读不到它,但它确实存在!
第20行代码执行结果如下:在18行结束事务后,可以看到id=1的name值为:name1_v2,并不等于name1_v3!第二次select 明明读到有name=name1的数据啊,可为啥第16行的update语句没有修改成功呢?因为幻读。你读到的name1,但底层的数据早已变成name1_v2了。