对于MySQL的事务存在脏读、不可重复读和幻读的问题,那么这些问题是如何产生?如何通过事务的隔离级别来确保事务的数据预期可控?
查看当前会话的隔离级别:
select @@transaction_isolation;
设置会话的隔离级别,隔离级别由低到高设置依次为:
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
如果想设置全局的隔离级别就把session换成global即可;
MySQL事务中的脏读问题
脏读顾名思义就是读取到了脏数据,即当前事务读取到了其他事务还未提交的数据。
将当前会话隔离级别改为read uncommitted;
例子如上,事务B将张三更新为张老三,此时事务B还未提交,此时事务A读取到的数据就是张老三,而当事务B回滚后,事务A读取到的数据就是张三,读取到的数据是还未提交的数据,脏读现象在实际开发中一般不会遇到。
事务的不可重复读
不可重复读是指在同一次事务中前后查询到的数据不一致的问题,此时事务可以读取其他事务已经提交的数据。
此时将隔离级别设置为读已提交:read committed;
事务A在事务B执行前后的两次查询结构不一致,出现不可重复读的问题,影响了事务A的执行。事务A明明没有对张三的名字进行改变,为什么读取到的数据会发生改变,这就是不可重复读带来的问题,让程序运行变得不可预期。
事务中的幻读
幻读是指一次事务中前后数据量发生变化,用户产生不可预料的问题。
此时将事务的隔离级别设置为可重复读,也就是MySQL的默认隔离级别。
但是当我使用MySQL8默认的隔离级别实验时发现事务A在删除数据后事务B的插入会被阻塞,无法插入成功出现了锁等待超时退出的情况。InnoDB存储引擎在一定程度上会解决幻读问题,具体内容要看MVCC
事务的隔离级别
不可重复读和幻读容易混淆,不可重复读侧重数据的并发更新,而幻读侧重并发新增、删除这些会产生数据数量发生变化的场景。
从上到下,事务的隔离级别逐渐升高,但是数据的并发吞吐量逐渐下降。