任何支持事务的数据库,都必须具备四个特性,分别是:
也就是我们常说的事务ACID,这样才能保证事务中数据的正确性。而事务的隔离性就是指,多个并发的事务同时访问一个数据库时,一个事务不应该被另一个事务所干扰,每个并发的事务间要相互进行隔离。
一个事务读到另一个事务还没有提交的记录
-- 事务A
START TRANSACTION ;
insert into user(id, name) values(100, '张三');
-- COMMIT; 事务A 未提交
-- 此时事务B
select * from user where id = 100; //这里可以查询出 ‘张三’ 这条记录。
-- 如果事务A进行ROLLBACK,事务B就会发现查出了不存在的数据。这种现象就是脏读。
一个事务在自己没有更新数据库数据的情况,同一个查询操作执行两次或多次的结果应该是一致的;如果不一致,就说明为不可重复读。
-- 事务A
START TRANSACTION ;
select * from user where id = 100; //这里查询出 ‘张三’
-- 此时事务B 修改记录并提交
update user set name = '李四' where id = 100;
-- 事务A再次查询
select * from user where id = 100; //这里查询出 ‘李四’
-- 事务A在同一事务里查询两次结果不一致,这种现象叫不可重复读。
事务A读的时候读出了15条记录,事务B在事务A执行的过程中 增加 了1条,事务A再读的时候就变成了 16 条,这种情况就叫做幻影读。
-- 事务A
START TRANSACTION ;
select * from user where id < 200; //这里查询出10条记录
-- 此时事务B 新增用户 或 删除用户
insert into user(id, name) values(101, '牛二');
-- 事务A再次查询
select * from user where id < 200; //这里查询出11条记录
-- 事务A在同一事务里查询两次结果集记录数不一致,这种现象叫幻读。
在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。
如无特殊情况,基本是不会使用这种隔离级别的
这是系统中最常用的一种隔离级别,也是SQL Server和Oracle的默认隔离级别。这种隔离级别能够有效的避免脏读。当一个更新的事务没有提交时,另一个对更新数据进行查询的事务会因为无法查询而被阻塞,这种情况下,并发能力就相当的差,但数据库有快照(snapshot)的概念。快照既能保证数据一致性又不加锁。当一个更新的事务没有提交时,另一个对更新数据会从快照数据进行查询,这样既能保证并发能力又能保证数据一致性。读提交只能避免脏读,并不能避免不可重复读和幻读。
除非在查询中显示的加锁,不然,普通的查询是不会加锁的。加锁语句:
select * from user where id=100 lock in share mode; select * from user where id=100 for update;
它也是MySql的默认隔离级别,在这个级别下,普通的查询同样是使用的快照读,但是,和读提交不同的是,当事务启动时,就不允许进行修改操作(Update)了,而不可重复读恰恰是因为两次读取之间进行了数据的修改,因此,REPEATABLE_READ能够有效的避免不可重复读,但却避免不了幻读,因为幻读是由于插入或者删除操作(Insert or Delete)而产生的。
此处有例外,因为INNODB采用了Gap锁,所以RR级别可以避免幻读,想了解什么是Gap锁,请移步另一篇文章。// TODO 博客链接
这是数据库最高的隔离级别,这种级别下,事务串行化顺序执行,也就是一个一个排队执行,这种级别下,脏读、不可重复读、幻读都可以被避免,但是执行效率奇差,性能开销也最大,所以基本没人会用
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读RU | 可能 | 可能 | 可能 |
已提交读RC | 不可能 | 可能 | 可能 |
可重复读RR | 不可能 | 不可能 | 可能(INNODB不可能) |
串行化S | 不可能 | 不可能 | 不可能 |
select @@tx_isolation
set global transaction isolation level repeatable read;
select @@global.tx_isolation;
原文:https://www.cnblogs.com/PlacidZhang/p/10725641.html