Mysql 事务的四种隔离级别介绍

1、未提交读(READ UNCOMMITTED)

事务中的修改,即使没有提交,对于其他事务来说也是可见的。也就是说事务可以读取未提交的数据,也就是脏读(Dirty Read).

这是最低的隔离级别,实际的应用中一般不用这种隔离级别。

下面来模拟看下效果:

Session 1 :

mysql> show variables like '%isolation%';  【1】
+---------------+------------------+
| Variable_name | Value            |
+---------------+------------------+
| tx_isolation  | READ-UNCOMMITTED |
+---------------+------------------+
1 row in set (0.00 sec)

mysql> start transaction;                  【3】
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO test(num) VALUES(1);     【4】
Query OK, 1 row affected (0.00 sec)

Session 2 :

mysql> show variables like '%isolation%';  【2】
+---------------+------------------+
| Variable_name | Value            |
+---------------+------------------+
| tx_isolation  | READ-UNCOMMITTED |
+---------------+------------------+
1 row in set (0.00 sec)

mysql> select * from test;                【5】
+----+------+
| id | num  |
+----+------+
|  3 |    1 |
+----+------+
1 row in set (0.00 sec)

可见session 1中的更新还没有提交commit ,session 2中可以查询到session 1插入的结果。



2、提交读(READ COMMITTED)

一个事务所做的修改在提交前对于其他事务是不可见的。所以一个事务中两次执行同样的查询,有可能会产生不一样的结果,

因此这个隔离级别也成为不可重复读(nonrepeatable read)

下面来模拟看下效果(右边的序号表示执行顺序):

session 1 :

mysql> show variables like '%isolation%';   【1】
+---------------+----------------+
| Variable_name | Value          |
+---------------+----------------+
| tx_isolation  | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)

mysql> start transaction;                   【3】
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO test(num) VALUES(1);      【4】
Query OK, 1 row affected (0.00 sec)

mysql> COMMIT;                             【6】
Query OK, 0 rows affected (0.07 sec)

session 2 :

mysql> show variables like '%isolation%';      【2】
+---------------+----------------+
| Variable_name | Value          |
+---------------+----------------+
| tx_isolation  | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)

mysql> select * from test;                   【5】
Empty set (0.00 sec)

mysql> select * from test;                  【7】
+----+------+
| id | num  |
+----+------+
|  1 |    1 |
+----+------+
1 row in set (0.00 sec)

可见在commit 前,session 2是看不到session 1的更新结果的。



3、可重复读(REPEATABLE READ)

可重复读是mysql默认的隔离级别。可重复读保证了同一个事务中对同样记录的查询结果是一致的,所有他不会产生以上两种隔离级别的脏读和结果不一致情况,、

但是无法解决幻读的问题。

下面来模拟看下效果:

session 1 :

mysql> show variables like '%isolation%';   【1】
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)

mysql> start transaction;                      【3】
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test where num=2;          【5】
Empty set (0.01 sec)

mysql> select * from test where num=2;           【7】 说明没出现未提交读的脏读
Empty set (0.00 sec)

mysql> select * from test where num=2;            【9】 说明没出现提交读的情况
Empty set (0.00 sec)

mysql>  insert into test(num) values(2);        【10】
Query OK, 1 row affected (0.00 sec)

mysql> commit;                                  【11】
Query OK, 0 rows affected (0.03 sec)

mysql> select * from test where num=2;             【12】  Fuck ,刚不是跟我说没有num=2的记录么。   这就是幻读。
+----+------+
| id | num  |
+----+------+
|  4 |    2 |
|  5 |    2 |
+----+------+
2 rows in set (0.00 sec)

Session  2 :

mysql> show variables like '%isolation%';    【2】
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)

mysql> start transaction;                      【4】
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test(num) values(2);          【6】
Query OK, 1 row affected (0.00 sec)

mysql> commit;                                 【8】
Query OK, 0 rows affected (0.06 sec)


幻读问题可通过多版本并发控制(MVCC)来解决。


4、可串行话(SERIALIZABLE)

可串行话是最高的隔离级别,通过强制事务串行执行来避免前面说的问题。

简单说,他会在读取的每一行上都加上锁,所以会导致大量的超时 和锁争用问题。

实际应用中很少用到这个,除非需要确保数据的一致性并且没有并发的情况下才考虑。

下面来模拟看下效果:

Session 1 :

mysql> show variables like '%isolation%';
+---------------+--------------+
| Variable_name | Value        |
+---------------+--------------+
| tx_isolation  | SERIALIZABLE |
+---------------+--------------+
1 row in set (0.00 sec)

mysql> start transaction;                  【1】
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test;                   【3】
+----+------+ 
| id | num  |
+----+------+
|  1 |    2 |
+----+------+
1 row in set (0.00 sec)

Session 2 :

mysql> show variables like '%isolation%';    【2】
+---------------+--------------+
| Variable_name | Value        |
+---------------+--------------+
| tx_isolation  | SERIALIZABLE |
+---------------+--------------+
1 row in set (0.00 sec)

mysql> update test set num=5 where num=2;    【4】
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

可见,如果session 1不commit的话 ,session 2 就会一直等待 知道超时。



附:


猜你喜欢

转载自blog.csdn.net/kexiaoling/article/details/53858207