文章目录
在MySQL中,事务有4种隔离级别,分别为READ UNCOMMITTED(读未提交)、READ COMMITTED(读已提交)、REPEATABLE READ(可重复读)和SERIALIZABLE(串行化)。
脏读
READ UNCOMMITTED是事务隔离级别中最低的级别,该级别下的事务可以读取其他事务中未提交的数据,这种读取方式也被称为脏读。
下面以示例数据库employees.departments表为例演示脏读。首先,开启两个终端窗口,分别称为窗口A和窗口B。两个窗口都登录到MySQL数据库并切换到employees库。
1. 设置窗口B中事务的隔离级别
MySQL默认隔离级别是REPEATABLE READ,该级别可以避免脏读。为演示需求,将其隔离级别设置为READ UNCOMMITTED。
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)
# 设置隔离级别
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+------------------+
| Variable_name | Value |
+-----------------------+------------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+------------------+
1 row in set (0.00 sec)
2. 演示脏读
在窗口A中开启事务,并更新Sales部门名称为Sales2。
mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007 | Sales |
+---------+-----------+
1 row in set (0.01 sec)
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE departments SET dept_name='Sales2' WHERE dept_no='d007';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007 | Sales2 |
+---------+-----------+
1 row in set (0.00 sec)
此时不要提交事务,否则无法演示脏读现象。
切换到窗口B,查询该部门信息。
mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007 | Sales2 |
+---------+-----------+
1 row in set (0.01 sec)
从结果看,窗口B中可以看到修改后的部门名称,这是由于窗口B的事务隔离级别比较低,因此读取了窗口A中还没有提交的内容,出现了脏读情况。
脏读演示完毕,可以在窗口A中执行ROLLBACK命令回滚事务,让数据恢复初始状态。
3. 重新设置窗口B中事务的隔离级别
为防止脏读的发生,将B中事务的隔离级别设置为READ COMMITTED,该隔离级别可以避免脏读。
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+------