当前位置:网站首页>mysql-选择使用Repeatable read的原因
mysql-选择使用Repeatable read的原因
2022-06-23 16:44:00 【用户7353950】
问题背景
在mysql调优的过程中发现,mysql的默认隔离级别是可重复读(repeatable read),其他几类关系型数据库pg,以及sybase,oracle,sqlserver的默认的隔离级别都是读已提交(read committed)。
我们都知道隔离级别一共有四种,读未提交,读已提交,可重复读,序列化。隔离级别越高,并发性能也就越低。
疑问
1、那么mysql为什么要选择使用可重复读来作为默认的隔离级别呢?
2、可重复读,会带来哪些问题?
3、我们在开发过程中是否要修改默认值,将其改为我们常见的读已提交呢?
- 可重复读(Repeatable Read),简称为RR;
- 读已提交(Read Commited),简称为RC;
四种隔离级别
首先我们了解下四种隔离级别的区别。
- READ UNCOMMITTED :未提交读
- 读取未提交内容,所有事务可看到其他未提交事务的结果,很少实际使用
- 读取未提交的数据称为脏读(Dirty Read)
- READ COMMITTED :提交读
- 多数数据库的默认隔离级别(MySQL默认不是,默认为REPEATABLE-READ)
- 满足隔离的简单定义:一个事务只能看到已提交事务所做的改变
- 这种隔离级别,支持所谓的不可重读(Non-repeatable Read),同一事务的其他实例在该实例过程中可能有新commit,所以同一个select可能返回不同结果(同一个事务如何做到其他实例?)
- REPEATABLE READ :重复读
- 可重复读(MySQL默认事务隔离),但可能出现幻读(Phantom Read)
幻读(Phantom Read):当用户读取某范围数据行时,另一事务在此范围内插入新行,当用户再次读取此范围数据行时,读取到新的幻影行- InnoDB通过多版本并发控制MVCC机制解决该问题
- PS:新版MySQL采用
Next-Key锁来解决幻读问题
- SERIALIZABLE :串行化
- 最高隔离级别,强制事务排序(串行化),不会互相冲突
- 每个读数据航增加共享锁
- 此级别,可能导致大量超时现象和锁竞争
按事务隔离级别来说,级别越低数据一致性保障效果越差,而并发能力则越强。
为什么选择REPEATABLE READ?
mysql为什么选择使用可重复读来作为默认的隔离级别呢?
查了下文档,发现是有历史原因的,这和mysql的复制有关系,mysql的复制基于binlog,在配置文件中我们可以发现有一个参数binlog_format,binlog有三种格式
# binary logging format - mixed recommended
binlog_format=rowstatement:记录的是修改SQL语句row:记录的是每行实际数据的变更
mixed:statement和row模式的混合
在mysql5.0以前binlog只支持statement这种格式,这种格式在读已提交(read commited)这个隔离级别下主从复制是有bug的。
产生bug的原因如下:在主库上面执行先删除后插入,但是在从库如果binlog为statement格式,记录的顺序就是先插入后删除,从库执行的顺序和主库不一致,最后主库有数据,从库的数据被删掉了。
因此mysql将可重复读(repeatable read)作为默认的隔离级别!
当然在可重复读上面也有解决方案
一是使用间隙锁,当session 1执行delete语句的时候,锁住间隙,session 2就会被阻塞
二是将binlog_format设置为row格式,基于行的复制,就不会出现sql执行顺序不一样的问题。但是这个格式是mysql5.1以后才有的。由于历史的原因,mysql将默认的隔离级别设置为可重复读,并一直延续了下来,保证主从复制不出问题。
可重复读,会带来哪些问题?
1、隔离级别越高,并发能力越低。
2、在可重复读级别下,如果使用间隙锁的方式,那么导致死锁的几率比读已提交大的多。
select *from test where n_id < for update在可重复读级别下,可以锁住间隙,防止其他事务插入数据。
在读已提交级别下,不会影响插入,其他事务任然可以插入数据。3、在可重复读级别下,条件列未命中索引会锁表!而在读已提交隔离级别下只锁行
INSERT INTO order_record SELECT
* FROM
order_today
WHERE
pay_success_time < '2020-03-08 00:00:00';
在可重复读的隔离级别下,执行上面的sql,会对order_record加表锁,order_today逐步锁(扫描一个锁一个)
当pay_success_time没有索引,或者因为其它原因导致没有走锁定的时候order_today就会被锁住。测试:
mysql> show profiles;Empty set (0.00 sec)--默认隔离级别 REPEATABLE-READ mysql> select @@global.tx_isolation,@@session.tx_isolation;+-----------------------+------------------------+| @@global.tx_isolation | @@session.tx_isolation |+-----------------------+------------------------+| REPEATABLE-READ | REPEATABLE-READ |+-----------------------+------------------------+ row in set (0.00 sec)--测试1 使用默认的binlog_formatmysql> select @@binlog_format;+-----------------+| @@binlog_format |+-----------------+| STATEMENT |+-----------------+ row in set (0.00 sec)--session 1 mysql> insert into test2 select * from test limit ;
Query OK, rows affected, warning (31.10 sec)
Records: Duplicates: Warnings: --session 2 可以看到插入test的数据会一直等待session 1执行完成才能插入mysql> insert into test values('4028e481513e66bc015156c3e359001a','1','1');
Query OK, row affected (29.48 sec)--测试2 将binlog_format设置为rowmysql> set global binlog_format='row';
Query OK, rows affected (0.00 sec)
mysql> select @@binlog_format;+-----------------+| @@binlog_format |+-----------------+| ROW |+-----------------+ row in set (0.00 sec)-- session 1mysql> insert into test2 select * from test limit ;
Query OK, rows affected (32.09 sec)
Records: Duplicates: Warnings: --session 2 可以看到session 1不会阻塞session 2 的插入mysql> insert into test values('4028e481513e66bc015156c3e359001a','1','1');
Query OK, row affected (0.00 sec)--测试3 将binlog_format设置为mixedmysql> set global binlog_format='mixed';
Query OK, rows affected (0.00 sec)
mysql> select @@binlog_format;+-----------------+| @@binlog_format |+-----------------+| MIXED |+-----------------+ row in set (0.00 sec)--session 1mysql> insert into test2 select * from test limit ;
Query OK, rows affected (32.16 sec)
Records: Duplicates: Warnings: --session 2 ,session 1会阻塞session2的插入mysql> insert into test values('4028e481513e66bc015156c3e359001a','1','1');
Query OK, row affected (30.71 sec)
mysql在默认隔离级别可重复读(REPEATABLE-READ)时,binlog_format设置为statement和mixed都会阻塞,设置为row模式时不会阻塞。insert into select 有两种阻塞方式,一种是逐行锁住,一种是全表锁住。详情
解决这个阻塞的方式有两种:一是可以先把查询出来的数据落地,然后在还原到另外一张表。或者将binlog_format改为row
最好的方式是使用读已提交的模式,并且将binlog_format设置为row
另外。在mysql中设置隔离级别为读已提交时,binlog_format如果设置为statement插入数据的时候会报错:
--默认binlog_format=statement会报错mysql> create table test3(id int)engine=innodb;
Query OK, rows affected (0.16 sec)
mysql> insert into test3 values();
ERROR (HY000): Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'--设置binlog_format=row无问题mysql> set session binlog_format=row;
Query OK, rows affected (0.00 sec)
mysql> insert into test3 values();
Query OK, row affected (0.06 sec)--设置binlog_format=mixed无问题mysql> set session binlog_format=mixed;
Query OK, rows affected (0.00 sec)
mysql> insert into test3 values();
Query OK, row affected (0.07 sec)
报错的原因是因为read committed可能会导致不可重复读,也就是说可以读取到后面进入并提交的数据,如果基于STATEMENT格式的话,会导致主从数据不一样,因为STATEMENT是基于SQL语句的复制模式。使用读已提交的时候,binlog_format只能设置为row或者mixed。建议使用row
总结
1、mysql为什么选择使用可重复读来作为默认的隔离级别?
原因是在mysql5.0以前binlog只支持statement这种格式,这种格式在读已提交(read commited)这个隔离级别下主从复制是有bug的,因此mysql将可重复读(repeatable read)作为默认的隔离级别!
2、可重复读会带来那些问题?
1)、隔离级别越高,并发能力越低。
2)、在可重复读级别下,如果使用间隙锁的方式,那么导致死锁的几率比读已提交大的多。
3)、在可重复读级别下,条件列未命中索引会锁表!而在读已提交隔离级别下只锁行
3、是否可以将mysql的默认隔离级别改为读已提交(read commited)
这个是可以的,在修改隔离级别为读已提交的同时,将binlog_format修改为row,可以提高并发能力。
边栏推荐
- The evolution of social structure and capital system brought about by the yuan universe
- C. Product 1 Modulo N-Codeforces Round #716 (Div. 2)
- 三分钟学会如何找回mysql密码
- The official Chinese course of zero foundation introduction jetpack compose is coming
- [go] calling Alipay to scan code for payment in a sandbox environment
- How can the points mall make profits
- qYKVEtqdDg
- 谈谈redis缓存击穿透和缓存击穿的区别,以及它们所引起的雪崩效应
- TensorRT Paser加载onnx 推理使用
- Query the size of each table in the database
猜你喜欢

微信小程序:酒店预计到店日期的时间选择器

Easyplayer mobile terminal plays webrtc protocol for a long time. Pressing the play page cannot close the "about us" page

Can the asemi fast recovery diodes RS1M, us1m and US1G be replaced with each other

网络远程访问树莓派(VNC Viewer)

The evolution of social structure and capital system brought about by the yuan universe

C#与数据库连接

ASEMI快恢复二极管RS1M、US1M和US1G能相互代换吗

Network remote access raspberry pie (VNC viewer)

内网渗透令牌窃取

Database Experiment 2 query
随机推荐
DataNode进入Stale状态问题排查
[qsetting and.Ini configuration files] and [create resources.qrc] in QT
《MPLS和VP体系结构》
Case analysis of camera power supply disturbed, seriously affecting image quality
【30. 串联所有单词的子串】
[network communication -- webrtc] analysis of webrtc source code -- supplement of pacingcontroller related knowledge points
Taishan Office Technology Lecture: four cases of using Italic Font
Lamp architecture that your girlfriend can read
The company recruited a tester with five years' experience and saw the real test ceiling
股票网上开户及开户流程怎样?在线开户安全么?
Jetpack Compose 与 Material You 常见问题解答
[30. concatenate substrings of all words]
QT布局管理器【QVBoxLayout,QHBoxLayout,QGridLayout】
Digital twin excavator of Tupu software realizes remote control
The R language uses the GT package and the gtextras package to display tabular data gracefully and beautifully: gt of the gtextras package_ The sparkline function visualizes the line plot of the group
元宇宙带来的社会结构和资本制度演变
The R language uses the RMSE function of the yardstick package to evaluate the performance of the regression model, the RMSE of the regression model on each fold of each cross validation (or resamplin
Rongyun: let the bank go to the "cloud" easily
Apache foundation officially announced Apache inlong as a top-level project
Opengauss database source code analysis series articles -- detailed explanation of dense equivalent query technology (Part 2)