mysql事务级别及可重复读/幻读情况模拟
mysql是大家常用的关系型数据存储数据库,为了保证一组操作的原子性(同时成功/同时失败)利用了事务。但是同一时间上读写可能存在的重复读、幻读/脏读等问题,就涉及到事务级别(默认级别:RR 可重复读 REPEATABLE-READ)设置。
事务级别分为:未提交可读(read uncommitted) 提交可读(read committed)可重复读(repeatable read)序列化(Serializable)
read uncommitted:事务未提交时即可读取,可能导致脏读。
read committed:事务提交后才可读取,但不可重复读(更新事务未提交前,其它查询为老值,但同一事务内存在更新前后查询不一致问题)(发生在update操作时)。
repeatable read: 可重复读,但是可能幻读(发生在insert操作时)。
幻读:A事务第一次查询时只存在一条,B事务新增一条记录,A事务再更新操作时更新成功两条。
幻读具体案例:
A事务:
SELECT * FROM `ims_user`; #查询结果1条
B事务:
INSERT ims_user ( NAME,STATUS) VALUES( 'c3',3); #新插入一条
COMMIT ;
A事务:
SELECT * FROM `ims_user`;#查询结果还是1条
UPDATE ims_user SET `status` = 4 WHERE `status`=3; #更新结果2条。
COMMIT ;
可重复读/幻读产生原因分析:
1、mvcc版本控制:我们可以先插入,后查询则结果正常。
验证步骤:
B事务:
INSERT ims_user ( NAME,STATUS) VALUES( 'c3',3); #新插入一条
COMMIT ;
A事务:
SELECT * FROM `ims_user`;#查询结果正常,新插入数据可查询到
2、无锁:“SELECT * FROM `ims_user`;”查询从快照中读,不存在锁。当发生“UPDATE/DELETE/INSERT”时为当前读,会产生行锁、表锁或者间隙锁(RR机制下)。
解决方案:
1、切换事务级别为Serializable。
2、悲观锁:SELECT * FROM `ims_user` for update; 或者 共享锁:SELECT * FROM `ims_user` lock in share mode;
Serializable:序列化事务机制,串行处理任务。牺牲性能,保证数据。
其它:
查看当前事务级别:SELECT @@tx_isolation;
查看当前事务是否自动提交:show VARIABLES LIKE 'autocommit';