1. 事务的并发问题(3个问题)
1)脏读:事务A读取了事务B更新的数据,然后事务B回滚,那么事务A读取到的数据就是脏数据
2)不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中对数据做了更新并提交,导致事务A多次读取同一数据的结果不一致,侧重于修改
3)幻读: 系统管理员A将数据库中所有的学生的成绩从具体分数改为ABCD等级,同时系统管理员B插入了或删除了一条具体分数的记录,导致A发现结束后还有一条数据没有改过来或是丢失了,就好像出现了幻觉一样
SessionA:
1)设置隔离级别read-uncommited
2)开启事务 start transaction
3) 查询
SessionB:
1) 设置隔离级别read-uncommited
2) 开启事务 start transaction
3) update
Session A:
4)再次查询
发现SessionA 读取到了 SessionB中的更改,出现了脏读
SessionA:
1)设置隔离级别read commited
2)开启事务 start transaction
3) 查询
select * from account;
select @@tx_isolation;
set session transaction ISOLATION level read COMMITTED;
SELECT * from account;
3) 查询
SessionB:
1) 设置隔离级别read-commited
2) 开启事务 start transaction
3) update
4) commit
set session TRANSACTION ISOLATION level read COMMITTED;
start TRANSACTION;
update account set balance = balance -50 where id =1
SELECT * from account;
SessionA:
5) 查询,
不能读取SessionB 未能commit 的改动,但是能读取到sessionB中已经commit的改动
SessionA:
1)设置隔离级别repeatable read
2)开启事务 start transaction
3) 查询
SessionB:
1)设置隔离级别repeatable read
2)开启事务 start transaction
3) insert or update
4) commit
SessionA:
4) 再次查询,又再次查询……多次查询, 发现不能读取 sessionB已经提交的改动,实现了可重复读
5) commit;
6) 再次查询(注意是commit后查询),发现可以读取sessionB已经提交的改动, 但是4)和该步骤 的查询结果不一样, 出现了幻读
SessionA:
1)设置隔离级别serializable
2)开启事务 start transaction
3) 查询
SessionB:
1)设置隔离级别serializable
2)开启事务 start transaction
3) 查询,可以查询到,但比较慢
4)insert or update ,经过漫长等待后,发现insert or update 均没有成功
SessionA:
4)commit;
SessionB:
5)insert or update
6) 查询 ,发现insert or update 成功了!!!
参考:
https://www.cnblogs.com/huanongying/p/7021555.html
参考文章的结论:
补充:
1、SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异
2、mysql中默认事务隔离级别是可重复读时并不会锁住读取到的行
3、事务隔离级别为读提交时,写数据只会锁住相应的行
4、事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁间隙锁、行锁、下一键锁的问题,从而锁住一些行;如果没有索引,更新数据时会锁住整张表。
5、事务隔离级别为串行化时,读写数据都会锁住整张表
6、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。