一、事务并发问题
1.脏读
A事务读取到B未提交事务的数据
2.不可重复读
同一事务查询结果不同,可能是其他事务提交了更新数据
3.幻读
A事务查询无数据,B事务这时插入数据,A事务还是没查到数据,但是插入会报错。
二、事务四种隔离级别
1.READ UNCOMMITTED 读未提交
脏读、不可重复读、幻读都会发生
2.READ COMMITTED 读已提交
脏读不会发生,不可重复读、幻读会发生
3.REPEATABLE READ 可重复读 (MySQL默认级别)
脏读,不可重复读不会发生,幻读会发生
4.SERIALIZABLE 串行化
脏读、不可重复读、幻读都不会发生
三、案例
1.查询、设置隔离级别
SELECT @@TRANSACTION_ISOLATION;
查询结果
MySQL默认的是REPEATABLE READ。
更改隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
成功后再查询一次,发现已经改变
session代表当前会话,也可以换成GLOBAL,代表全局,level后面则是设置四种隔离级别。
2.验证
准备工作:
创建测试数据库并创建测试表和数据
创建一个学生表
用到两个命令行登录mysql
(1)验证脏读
隔离级别设置为read uncommitted
开始事务查询一次,得到结果
然后我们在另一个命令行中运行更新的操作,但是不提交事务
在第一个命令行中再次查询一次,发现结果已改变
我们把隔离级别换成read committed后再重复上述操作
第一个命令行查询
然后另一个命令行执行更新的操作,但不提交事务
切回第一个命令行再次查询,发现值没有改变
第二个命令行执行commit提交事务,再用第一个命令行查询,发现值改变了
(2)验证不可重复读
开启事务查询
另一个命令行进行更新
再次查询发现数据没有变化,说明没有发生脏读
我们提交更新的事务,再次查询,发现数据更改了
三次查询的数据不一致,这就是不可重复读。当我们把隔离级别设置为repeatable read时就会发现同一事务三次查询的数据是一样的,把事务提交后再查询,数据发生了改变。
(3)验证幻读
查询id为3的数据,返回为空
在另一个命令行中添加id为3的数据并提交事务
切回第一个命令也添加id为3的数据,发现主键重复了
再查询一次还是为空
这就是幻读。
我们把隔离级别换成serializable,查询id为4的数据
另一个命令行中添加数据
不难发现光标一直在闪烁,是因为阻塞了,在等前面的事务执行完成,长时间没提交的话会报错超时
在第一个命令行中进行数据的添加并提交
这时候第二个命令行就会报错主键已存在