mysql · 18 4 月, 2021 0

数据库不可重复读、脏读、幻读概念

数据库相关概念的学习

不可重复读

不能重复读是指在事务开始之后, 第一次读取的结果集和第二次读取的结果集不一致。

TRANSACTION1 TRANSACTIONS2
select * from p where id < 5
insert into p values (2)
commit
select * from p where id < 5

以上是作为一个正确的事务执行顺序, 如果TRANSACTION1两次执行了相同的SQL语句, 但是却获取了TRANSACTION2插入的结果。 这种主要是事务级别为READ COMMITTED时出现。

脏读

脏读是指的事务之间读取了其他事务没有提交的数据

TRANSACTION1 TRANSACTIONS2
BEGIN
SELECT * FROM p WHERE id < 5;
BEGIN
INSERT INTO p VALUES (2);
SELECT * FROM p WHERE id < 5

TRANSACTION1两次读取之间,事务TRANSACTION2插入了一条数据,但是没有提交,如果TRANSACTION1读取到了TRANSACTION2插入的数据, 这就产生了数据脏读. 这种情况主要出现在READ UNCOMMITTED的隔离级别之下。

幻读

幻读指的是两个事务之间, 操作相同的数据差生了冲突,导致另外一个事务无法正常执行业务的后续操作。

TRANSACTION1 TRANSACTIONS2
BEGIN
SELECT * FROM WHERE id = 1
BEGIN
INSERT INTO p VALUES (1)
INSERT INTO p VALUES (1)
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

以上主要操作了两个事务, 在TRANSACTION1中判断id=1的记录不存在, 准备插入一个id = 1的记录, 但是在这期间, TRANSACTION2插入了一条id = 1的记录, 这是导致了TRANSACTION1插入失败,但是当通过select * from where id = 1查询这条记录时, 却查询不到这条记录, 这是因为mysql采用了REPEATABLE READ的策略,导致了其他事务提交的数据不能被读取到。

解决幻读最好的办法就是通过的方式对需要操作的数据加锁, 防止事务执行失败。

NOTE: 在Serializable隔离级别之下, 查询语句默认的都会加锁(共享锁(S)), 因此这种的话, TRANSACTION1的第三部可以正常执行,TRANSACTION2等待锁的释放.