在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。
幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
它和不可重复读(Non Repeatable Read)的区别就是:
不可重复读:两次读取之间,其他事务对于某一行数据的修改或者删除造成。这个行级锁就可以解决了。
而幻读(Phantom Read):两次读取之间,其他事务添加了一行数据。表级锁才可以解决。
但是在实际开发中,表级锁我们基本上是您能不用就不用的,就是行级锁,都是需要慎用的。
我们接着使用employees表的数据:
然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:
第一步:执行事务A,SELECT * FROM employees WHERE employee_id= 99;
第二步:执行事务B,INSERT INTO employees (employee_id, last_name) VALUES (99, 'Test');
第三步:执行事务B,COMMIT;
第四步:执行事务A,SELECT * FROM employees WHERE employee_id = 99;
第五步:执行事务A,UPDATE employees SET last_name = 'Ace' WHERE employee_id = 99;
第六步:执行事务A,SELECT * FROM employees WHERE employee_id = 99;
第七步:执行事务A,COMMIT;
事务B在第1步第一次读取id=99的记录时,读到的记录为空,说明不存在employee_id =99的记录。随后,事务A在第2步插入了一条employee_id =99的记录并提交。事务B在第4步再次读取employee_id =99的记录时,读到的记录仍然为空,但是,事务B在第5步试图更新这条不存在的记录时,竟然成功了,并且,事务B在第6步再次读取employee_id =99的记录时,记录出现了。
可见,幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。
Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。
虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。
默认隔离级别
如果没有指定隔离级别,数据库就会使用默认的隔离级别。