MySQL事务隔离级别测试
OrdinaryRoad
0
25
144
0
READ UNCOMMITTED, READ COMMITTED, REPEATED READ, SERIALIZABLE
友情提示:此篇文章大约需要阅读 10分32秒
# 一些命令
## 设置是否自动commit
MySQL默认事务都是自动提交的
```mysql
SELECT @@AUTOCOMMIT;
SET AUTOCOMMIT = 0;
```
## 设置当前会话隔离级别
> 旧版本:tx_isolation,新版本:transaction_isolation。
ISOLATION_LEVEL
- READ UNCOMMITTED
- READ COMMITTED
- READ REPEATABLE
- SERIALIZABLE
```mysql
SHOW GLOBAL VARIABLES like '%isolation';
SELECT @@tx_isolation;
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL ${ISOLATION_LEVEL};
```
# 测试
建表并初始化
```mysql
DROP TABLE IF EXISTS table1;
CREATE TABLE table1(
id BIGINT(20) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10) null
);
INSERT INTO table1(id,name) VALUES(null,1),(null,2),(null,3),(null,4),(null,5),(null,6),(null,7),(null,8),(null,9),(null,10);
SELECT * FROM table1;
```
## 赃读问题
**脏读:事务A读取到事务B修改后但回滚的数据,破坏了事务的隔离性**
### 准备
会话隔离级别设置为READ UNCOMMITED,取消自动提交,并查看是否修改
```mysql
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET AUTOCOMMIT = 0;
SELECT @@TRANSACTION_ISOLATION, @@AUTOCOMMIT;
```
### 流程
| 事务A | 事务B | 说明 |
| ---------------------------------- | ----------------------------------------------------- | ------------------------------------------------------ |
| | BEGIN; | 开始一个事务B |
| | UPDATE table1 SET table1.name = '姓名1' WHERE id = 1; | B更新记录 |
| SELECT * FROM table1 WHERE id = 1; | | 因为B后续会发生回滚,所以A读取到的是脏数据,发生了赃读 |
| | ROLLBACK; | B回滚,需要手动commit |
| | COMMIT; | B提交,结束事务 |
## 不可重读问题
**不可重读:事务A先后两次读取同一条记录,在此之间事务B修改并提交了A读取的数据,导致事务A两次数据不一致,破坏了一致性**
### 准备
隔离级别:READ COMMITTED,取消自动提交
```mysql
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET @@AUTOCOMMIT = 0;
SELECT @@TRANSACTION_ISOLATION, @@AUTOCOMMIT;
```
### 流程
| 事务A | 事务B | 说明 |
| ---------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------ |
| | BEGIN; | 开始一个事务B |
| SELECT * FROM table1 WHERE id = 1; | | A读取记录,结果为1,1 |
| | UPDATE table1 SET table1.name = '姓名1' WHERE id = 1; | B更新记录 |
| SELECT * FROM table1 WHERE id = 1; | | A重复读取记录,结果变为1,姓名1,在一个事务中,重复读取同一条数据结果却不一样,发生了不可重读 |
| | COMMIT; | B提交,结束事务 |
## 幻读
**幻读:事务A先后两次读取数据集合,在此之间事务B插入或删除了记录,导致事务A两次读取的集合发生变化,无法进行插入等操作,破坏了一致性**
### 准备
删除ID7 8 9的记录
```mysql
DELETE FROM table1 WHERE id BETWEEN 7 AND 9;
```
隔离级别:REPEATABLE READ,取消自动提交
```mysql
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET @@AUTOCOMMIT = 0;
SELECT @@TRANSACTION_ISOLATION, @@AUTOCOMMIT;
```
### 流程
| 事务A | 事务B | 说明 |
| ---------------------------------- | ---------------------------------- | ----------------------------------------------------- |
| BEGIN; | | 开始一个事务A |
| SELECT * FROM table1 WHERE id = 7; | | A查询id为7的数据,发现为空,准备插入一条id为7的数据 |
| | BEGIN; | B开始一个事务 |
| | SELECT * FROM table1 WHERE id = 7; | B查询id为7的数据,发现为空,也准备插入一条id为7的数据 |
| | INSERT INTO table1 VALUES(7,7); | B插入一条id为7的数据 |
| | COMMIT; | B提交,结束事务 |
| INSERT INTO table1 VALUES(7,7); | | A插入一条id为7的数据,此时却提示主键重复 |
| SELECT * FROM table1 WHERE id = 7; | | A颇为吃惊,又查了一下id为7的数据,发现确实为空 |
| INSERT INTO table1 VALUES(7,7); | | A又试图插入,还是失败 |
| COMMIT; | | A骂骂咧咧地结束了事务,今天出现幻觉了 |
本文作者:OrdinaryRoad
本文链接: 版权声明:本文为OrdinaryRoad博客博主 OrdinaryRoad 的原创文章,遵循
CC BY-SA 4.0
许可协议,转载请附上本文链接及本声明。
评论
楼主暂时不想被别人评论哦~
已自动恢复阅读位置、日/夜间模式参数