Mysql RC/RR隔离原理和区别 不可重复读和可重复读
mysql四种隔离级别: 1.未提交读(READ UNCOMMITED)脏读 2.已提交读 (READ COMMITED)简称(RC) 不可重复读 3.可重复读(REPEATABLE READ)简称(RR) 4.可串行化(SERIALIZABLE) 这个不用验证了,所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰了,一般不用,性能特别低。
测试1 ,采用mysql 默认的隔离级别 RR ,启动A、B两个事务对比,阿拉伯数字递增代表事务执行的时间顺序
测试2 ,隔离级别设置为 RC ,启动A、B两个事务对比,阿拉伯数字递增代表事务执行的时间顺序
总结∶
可重复读级别下(RR),开启事务之后第一个select才会生成快照,而不是事务一开始就生成快照。 >> 在一个事务内 本事务未提交之前(外部事务已提交),查询的仍然是上一次该数据快照。而不是最新数据。 读已提交级别下(RC),每次select都会生成一个快照。 >> 在一个事务内 本事务未提交之前(外部事务已提交),查询的是最新数据。
Oracle 默认使用READ COMMITTED(读已提交)隔离级别 MySQL默认使用REPEATABLE(可重复读)隔离级别
以下是测试步骤: 1.mysql客户端SQLyog测试无效,需要通过 MySQL 8.0 Command Line Client客户端来测试。 开启2个MySQL 8.0 Command Line Client客户端
2.数据库默认事务是自动提交模式,查看和修改提交模式 #查看 SELECT @@autocommit; #关闭自动提交 SET @@autocommit = 0; #开启自动提交 SET @@autocommit = 1;
-- 查看当前会话的事务隔离级别 SELECT @@transaction_isolation; # REPEATABLE-READ -- 查看全局的事务隔离级别 SELECT @@GLOBAL.transaction_isolation; # REPEATABLE-READ
修改隔离级别 READ UNCOMMITTED:允许事务读取其他未提交的事务所做的修改。但是,会出现脏读、不可重复读和幻读等问题。 READ COMMITTED:只允许事务读取已经提交的事务所做的修改。在同一个事务内,对同一行数据的查询可能返回不同的结果。 REPEATABLE READ:事务执行期间,保证多次读取同一数据结果一致。但是,可能出现幻读问题。 SERIALIZABLE:最高级别的隔离级别,完全串行化事务执行。确保每个事务对数据库的读写操作是相互独立的。
概念: 并发事务会出现更新丢失、脏读、不可重复读,幻读。 更新丢失:当两个或多个事务更新同一行记录,会产生更新丢失现象。回滚覆盖,一个事务回滚操作,把其他事务已提交的数据给覆盖了;提交覆盖,一个事务提交操作,把其他事务已提交的数据给覆盖了 脏读:一个事务读取到了另一个事务修改但未提交的数据 不可重复读:一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致 幻读:在同一个事务中,前后两次查询同一个范围的数据时,发现有新的数据插入,导致结果集不一致的情况。
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;
手动控制事务 开启事务:BEGIN; 和 START TRANSACTION; 在功能上是等价的。它们都会开始一个新的事务。 提交事务:COMMIT; 回滚事务:ROLLBACK;
#创建测试表 CREATE TABLE `isolation_level_test` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) DEFAULT NULL, `age` INT(11) DEFAULT NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8;
##初始化1条记录 INSERT INTO `isolation_level_test` (`id`, `name`, `age`, `create_time`) VALUES (1, 'forlan3', 11, '2024-05-29 13:45:11'); # 5
# 对应上面的图示 #窗口1 BEGIN; # 1 SELECT * FROM isolation_level_test; # 3 SELECT * FROM isolation_level_test; # 7 COMMIT; # 8 SELECT * FROM isolation_level_test; # 9
#窗口2 BEGIN; # 2 SELECT * FROM isolation_level_test; # 4 INSERT INTO `isolation_level_test` (`id`, `name`, `age`, `create_time`) VALUES (11, 'forlan3', 12, '2024-05-29 13:45:11'); # 5 COMMIT; # 5 SELECT * FROM isolation_level_test; # 6
## 扩展 SERIALIZABLE 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰了。 窗口1 在查询的时候,如果窗口2 新增的数据,但是没有提交,窗口1就卡在那里,查询不出结果。只有等窗口2提交或回滚,窗口1才可以查询出来结果。