Mysql RC/RR隔离原理和区别 不可重复读和可重复读
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才可以查询出来结果。