数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。(保持怀疑)
幻读
什么是幻读?
幻读不是说两次读取的结果集不同,幻读侧重的是某一次的select操作得到的结果所表征的数据状态无法支撑后续的业务操作。更具体一些:select某记录是否存在,不存在,准备插入此记录,但执行insert时发现此记录已经存在,无法插入,此时就发生了幻读。
实现隔离级别的方式就是加锁。(保持怀疑)
示例(来自网络)
table users: id primary key
事务T1
事务T2
step1 T1: SELECT * FROM
users
WHEREid
= 1;
step2 T2: INSERT INTOusers
VALUES (1, ‘big cat’);
step3 T1: INSERT INTOusers
VALUES (1, ‘big cat’);
step4 T1: SELECT * FROMusers
WHEREid
= 1;
T1 :主事务,检测表中是否有 id 为 1 的记录,没有则插入,这是我们期望的正常业务逻辑。
T2 :干扰事务,目的在于扰乱 T1 的正常的事务执行。
在 RR 隔离级别下,step1、step2 是会正常执行的,step3 则会报错主键冲突,对于 T1 的业务来说是执行失败的,这里 T1 就是发生了幻读,因为 T1 在 step1 中读取的数据状态并不能支撑后续的业务操作,T1:“见鬼了,我刚才读到的结果应该可以支持我这样操作才对啊,为什么现在不可以”。T1 不敢相信的又执行了 step4,发现和 setp1 读取的结果是一样的(RR下的 MMVC机制,因为事务t2在事务t1之后,所以t1看不到t2插入的数据)。此时,幻读无疑已经发生,T1 无论读取多少次,都查不到 id = 1 的记录,但它的确无法插入这条他通过读取来认定不存在的记录(此数据已被T2插入),对于 T1 来说,它幻读了。
MySQL事务隔离级别
查看MySQL事务隔离级别
1.查看当前会话隔离级别
select @@tx_isolation;
2.查看系统当前隔离级别
select @@global.tx_isolation;
3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;
4.设置系统当前隔离级别
set global transaction isolation level repeatable read;
5.命令行,开始事务时
set autocommit=off 或者 start transaction
1 | # 查看当前会话隔离级别 |
隔离级别的分类
- 读未提交 Read Uncommitted(在本次事务中可以读到其他事务中没有提交的数据 - 脏数据)
- 读已提交 Read Committed (只能读到其他事务提交过的数据。如果在当前事务中,其他事务有提交,则两次读取结果不同)
- 可重复读 Repeatable Read (默认,保证了事务中每次读取结果都相同,而不管其他事物是否已经提交。会出现幻读)
- 序列化 Serializable (隔离级别中最严格的,开启一个 serializable 事务,那么其他事务对数据表的写操作都会被挂起)
参考文献
[1]mysql 幻读的详解、实例及解决办法:https://segmentfault.com/a/1190000016566788
[2]理解 MySQL 中的四种隔离级别:https://learnku.com/articles/13849/understanding-four-isolation-levels-in-mysql