文章目录

  • 一. 准备工作
  • 1.1 准备表
  • 1.2 查看事务隔离级别
  • 1.3 修改自动提交配置
  • 二、在读未提交的隔离级别下
  • 2.1 修改隔离级别
  • 2.2 代码演示
  • 2.3 总结
  • 三、在读已提交的隔离级别下
  • 3.1 修改隔离级别
  • 3.2 代码演示
  • 3.4 总结
  • 四 在可重复读的隔离级别下
  • 4.1 修改隔离级别
  • 4.2代码演示
  • 总结
  • 总结



一. 准备工作

本文章是基于MySQL8.0下演示,开启俩个窗口,为了方便说明,下面我会使用事务1和事务2来演示

1.1 准备表

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  1 | 小明 |    1 |
|  2 | 小红 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

1.2 查看事务隔离级别

mysql> show variables like 'transaction%';
+----------------------------------+-----------------+
| Variable_name                    | Value           |
+----------------------------------+-----------------+
| transaction_alloc_block_size     | 8192            |
| transaction_allow_batching       | OFF             |
| transaction_isolation            | REPEATABLE-READ |
| transaction_prealloc_size        | 4096            |
| transaction_read_only            | OFF             |
| transaction_write_set_extraction | XXHASH64        |
或使用
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+

1.3 修改自动提交配置

mysql> show variables like '%autocommit%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> set autocommit = off;
Query OK, 0 rows affected (0.00 sec)

二、在读未提交的隔离级别下

2.1 修改隔离级别

mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

2.2 代码演示

对事务1进行修改操作,不提交事务

mysql> update student set name = '小黑' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

事务2进行查询操作

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  2 | 小红 |    1 |
|  1 | 小黑 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

2.3 总结

通过代码演示可以看出,事务1对数据进行了修改操作,但没有提交事务,这时,事务2进来,对数据进行了查询操作,查询到了事务1没有提交的数据.这就是脏读产生的原因.脏读只会在读未提交下产生.

三、在读已提交的隔离级别下

3.1 修改隔离级别

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

3.2 代码演示

事务1进行修改操作,并不提交事务

mysql> update student set name = '小绿' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

事务2进行查询操作

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  2 | 小红 |    1 |
|  1 | 小黑 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

总结
可以看出,在读已提交的隔离级别下,对事务1进行了修改,事务2没有查询到修改的数据,这样就避免了会读到脏数据的,解决了脏读问题。但不能避免不可重复读问题,下面我会通过代码继续演示。

事务1进行修改操作,并未提交事务

mysql> update student set name='小蓝' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

这时,事务2进行读取数据

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  2 | 小红 |    1 |
|  1 | 小黑 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

事务1提交了事务

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

事务2再次读取数据

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  2 | 小红 |    1 |
|  1 | 小蓝 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

3.4 总结

在读已提交的隔离级别下,虽然解决了不可重复读的问题,但是没有解决不可重复读的问题,不可重复读就是事务2在事务1提交前读取到的数据,与 事务1提交后读取的数据不一致.

四 在可重复读的隔离级别下

4.1 修改隔离级别

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

4.2代码演示

事务1进行修改操作,并未提交事务

mysql> update student set name = '小白' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

事务2读取数据

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  2 | 小红 |    1 |
|  1 | 小蓝 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

事务1提交事务

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

事务2读取数据

mysql> select * from student;
+----+------+------+
| id | name | tid  |
+----+------+------+
|  3 | 小张 |    1 |
|  2 | 小红 |    1 |
|  1 | 小蓝 |    1 |
|  4 | 小李 |    2 |
|  5 | 小王 |    2 |
+----+------+------+
5 rows in set (0.00 sec)

总结
可以看出,在可重复读的隔离级别下,没有产生脏读,不可重复读的问题,但有可能产生幻读的问题.下面我会通过代码进行演示.
事务2查询 name=小紫 的数据

mysql> select * from where name = '小紫';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where name = '小紫'' at line 1

事务1插入一条 name=小紫 的数据,并提交事务

mysql> insert into student value('6','小紫','2');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

事务2再去查询 name=小紫 的数据

mysql> select * from where name = '小紫';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where name = '小紫'' at line 1

事务2插入一条 name=小紫 的数据

mysql> insert into student value('6','小紫','2');
ERROR 1062 (23000): Duplicate entry '6' for key 'PRIMARY'

总结

时间点

事务2

事务1

1

开启事务

2

开启事务

3

查询数据“小紫”,不存在

4

插入数据“小紫”

5

提交事务

6

查询数据“小紫”,不存在

7

插入数据“小紫”,不成功

总结

下面我总结了各种隔离级别下可能出现的问题.

gorm 设置mysql隔离级别 mysql隔离级别实现_gorm 设置mysql隔离级别