前言
本文记录下MySQL隔离级别,以及并发情况下不同隔离级别可能导致的问题分析,深化下对MySQL隔离级别的理解
一、MySQL隔离级别类型
READ-UNCOMMITTED | 读未提交 |
READ-COMMITTED | 提交读 |
REPEATABLE-READ | 可重复读 |
SERIALIZABLE | 串行化读 |
二、MySql事务并非情况下可能出现的问题
1.脏读(读取到未提交的数据)
这个很容易理解,其中一个事务读取到未提交事务的数据(未提交事务有可能被回滚,或者在未提交之前发生改变),应该说这种情况不论在那个系统中都是不符合业务需求的,所以应该避免这个问题
2.不可重复读取
不可重复读的意思是,同一条数据在同一个事务执行期间,数据可能不一样,这样就不支持重复读取了,应该要保证重复读取数据是一样的
3.幻读
幻读值得是在一个范围查询中后一次查询查询到前面查询没有的数据
并发情况下不同事务隔离级别可能出现的问题
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交 | 可能 | 可能 | 可能 |
提交读 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
串行化读 | 不可能 | 不可能 | 不可能 |
三、验证不同事务隔离级别下可能出现的问题
1.修改MySQL事务提交方式
查看事务提交 SELECT @@autocommit;
默认是1 代表自动提交,SET autocommit = 0; 就改成手动提交了 (方便后面测试)
2.修改事务隔离级别
修改当前会话隔离级别
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;
修改全局会话隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
接下来开始验证了,先准备一个表
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`user_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '姓名',
`age` int(0) NULL DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
验证脏读问题
打开两个客户端
这样就验证了读未提交隔离级别下脏读的问题,对应的测试sql是这样的
SELECT * FROM sys_user;
INSERT INTO `sys_user`( `user_name`, `age`) VALUES ( '测试', 352);
然后我们将隔离级别改成提交读,会发现脏读问题解决了
验证不可重复读问题
可重复读以下的隔离级别都可能导致不可重复读问题
然后我们把隔离级别改成可重复读再试试,可以验证可重复读隔离级别可以解决不可重复读问题
可重复读隔离级别,在事务期间是从开始时拿到的ReadView快照里面读数据
验证幻读问题
幻读问题在读未提交,提交读隔离级别下很好验证,将隔离级别改成提交读
然后我们将隔离级别改成 串行化读
这里说明串行化读可以解决幻读问题
总结
另外 可重复读隔离级别是读取当前快照,按我这边理解不太容易产生幻读,还没理太清,但实际上这个隔离级别也是可能出现幻读的,具体参考下这位大佬的文章