如上图,四种隔离级别分别实现了不同的功能,看是级别越高也代表着需要的锁越多,更容易产生阻塞。
接下来通过实验介绍这几种读
(1)脏读
把隔离级别调为READ-UNCOMMITTED
root@localhost:MySQL.sock 01:30:05 [(none)]>set global tx_isolation = 'READ-UNCOMMITTED';
root@localhost:mysql.sock 01:30:22 [(none)]>show global variables like '%iso%';
+---------------+------------------+
| Variable_name | Value |
+---------------+------------------+
| tx_isolation | READ-UNCOMMITTED |
+---------------+------------------+
1 row in set (0.00 sec)
会话1:
root@localhost:mysql.sock 01:34:06 [lala]>select * from score;
Empty set (0.00 sec)
root@localhost:mysql.sock 01:34:53 [lala]>begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost:mysql.sock 01:35:23 [lala]>insert into score values(1,'xiaohong',99);
Query OK, 1 row affected (0.00 sec)
还没有提交
会话2:
root@localhost:mysql.sock 01:37:08 [lala]>select * from score;
+------+----------+-------+
| id | name | score |
+------+----------+-------+
| 1 | xiaohong | 99 |
+------+----------+-------+
1 row in set (0.00 sec)
会话2可以直接读到会话1还没有提交的数据。
(2)不可重复读
root@localhost:mysql.sock 01:30:05 [(none)]>set global tx_isolation = 'READ-COMMITTED';
root@localhost:mysql.sock 01:30:22 [(none)]>show global variables like '%iso%';
+---------------+------------------+
| Variable_name | Value |
+---------------+------------------+
| tx_isolation | READ-COMMITTED |
+---------------+------------------+
1 row in set (0.00 sec)
会话1:
root@localhost:mysql.sock 01:49:00 [lala]>begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost:mysql.sock 01:49:08 [lala]>update score set id=3;
Query OK, 1 row affected (0.00 sec)
会话2:
root@localhost:mysql.sock 01:49:14 [lala]>select * from score;
+------+----------+-------+
| id | name | score |
+------+----------+-------+
| 1 | xiaohong | 99 |
+------+----------+-------+
1 row in set (0.00 sec)
会话1:
root@localhost:mysql.sock 01:49:20 [lala]>commit;
Query OK, 0 rows affected (0.00 sec)
会话2:
root@localhost:mysql.sock 01:49:47 [lala]>select * from score;
+------+----------+-------+
| id | name | score |
+------+----------+-------+
| 3 | xiaohong | 99 |
+------+----------+-------+
1 row in set (0.00 sec)
会话2第一次只读到id的值是1,但以为会话1提交,会话2第二次读到id的值是3.
(3)幻读
会话1:
root@localhost:mysql.sock 01:49:00 [lala]>begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost:mysql.sock 01:49:08 [lala]>insert into score values(2,'xiaoming',65);
Query OK, 1 row affected (0.00 sec)
会话2:
root@localhost:mysql.sock 01:49:14 [lala]>select * from score;
+------+----------+-------+
| id | name | score |
+------+----------+-------+
| 1 | xiaohong | 99 |
+------+----------+-------+
1 row in set (0.00 sec)
会话1:
root@localhost:mysql.sock 01:49:20 [lala]>commit;
Query OK, 0 rows affected (0.00 sec)
会话2:
root@localhost:mysql.sock 01:50:27 [lala]>select * from score;
+------+----------+-------+
| id | name | score |
+------+----------+-------+
| 3 | xiaohong | 99 |
| 2 | xiaoming | 65 |
+------+----------+-------+
2 rows in set (0.00 sec)
会话2第一次只读到1条数据,但以为会话1提交,会话2第二次读到两条记录
ps:不可重复读是因为数据的update导致,而幻读是因为数据的delete或者insert导致
mysql中的innodb的事务默认隔离级别是Repeatable read(可重复读),但是它不是普通的Repeatable read,它在可重复读的基础上避免了幻读。是通过臭名昭著的gop锁实现不可重复读。
root@localhost:mysql.sock 01:17:04 [(none)]>show global variables like '%iso%';