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)来解决。
可串行话是最高的隔离级别,通过强制事务串行执行来避免前面说的问题。
简单说,他会在读取的每一行上都加上锁,所以会导致大量的超时 和锁争用问题。
实际应用中很少用到这个,除非需要确保数据的一致性并且没有并发的情况下才考虑。
下面来模拟看下效果:
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 就会一直等待 知道超时。
附: