t (0.01 sec)
mysql>
但是如果在REPEATABLE-READ事务隔离级别下,总是读取事务开始时的数据,所以得到的结果截然不同,如下所示:
mysql> show variables like 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
mysql> select * from t1 where a=1;
+---+----+----+
| a | b | c |
+---+----+----+
| 1 | c0 | c2 |
+---+----+----+
1 row in set (0.00 sec)
mysql> select * from t1 where a=111;
Empty set (0.00 sec)
mysql>
对于READ-COMMITTED的事务隔离级别而言,从数据库理论的角度来看,其实违反了事务ACID的I的特性,既是隔离性,整理成时序表,如下图所示。
| Time |
Session A |
Session B |
| | time 1 |
Begin; Select * from t1 where a=1;有记录 |
|
| | time 2 |
|
Begin; Update t1 set a=111 where a=1; |
| | time 3 |
Select * from t1 where a=1;有记录 |
|
| | time 4 |
|
Commit; |
| | time 5 |
Select * from t1 where a=1; 无记录 |
|
| V time 6 |
Commit; |
|
如果按照ACID原理中的I原理隔离性,在整个会话中Session A中,Select * from t1 where a=1;应该查询出来的数据保持一直,但是在time 5那一刻 Session A未结束的时候,查询出来的结果已经变化了和time 1、time 3已经不一致了,不满足ACID的隔离性。
5,SELECT ... FOR UPDATE && SELECT ... LOCK IN SHARE MODE
默认情况下,innodb存储引擎的select操作使用一致性非锁定读,但是在某些情况下,需要对读操作进行加锁。Innodb存储引擎对select语句支持2种添加锁操作;
SELECT ... FOR UPDATE 对于读取的行记录加一个X排它锁,其他事务如果要对这些行进行dml或者select操作都会被阻塞。
SELECT ... LOCK IN SHARE MODE 对于读取的行记录添加一个S共享锁。其它事务可以向被锁定的行加S锁,但是不允许添加X锁,否则会被阻塞。
对于一致性 非锁定读,即使读取的行数已经被SELECT ... FOR UPDATE了,但是也是可以进行读取的。
PS:… FOR UPDATE以及LOCK IN SHARE MODE必须在一个事务中,如果事务commit了,锁也就释放了,所以在使用的时候务必加上begin;start transaction或者set autocommit=0;
例子如下:
会话A:开启事务,执行LOCK IN SHARE MODE;锁定
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM t1 WHERE a=1 LOCK IN SHARE MODE;
+---+----+----+
| a | b | c |
+---+----+----+
| 1 | c0 | c2 |
+---+----+----+
1 row in set (0.00 sec)
mysql>
同时在另外一个窗口开启会话B,执行dml操作
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update t1 set a=111 where a=1;
…这里会卡住,没有信息。
再开启一个会话C,查询INNODB_LOCKS、INNODB_TRX、INNODB_LOCK_WAITS表,就会看到锁的详细信息:
mysql> select * from INNODB_LOCKS;
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| 3015708:797:3:2 | 3015708 | X | RECORD | `test`.`t1` | PRIMARY | 797 | 3 | 2 | 1 |
| 3015706:797:3:2 | 3015706 | S | RECORD | `test`.`t1` | PRIMARY | 797 | 3 | 2 | 1 |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
2 rows in set (0.00 sec)
mysql>
mysql> select * from INNODB_LOCK_WAITS;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 3015708 | 3015708:797:3:2 | 3015706 | 3015706:797:3:2 |
+-------------------+-------------------+-----------------+------------------+
1 row in set (0.00 sec)
mysql>
mysql> SELECT it2.`trx_id` AS waiting_trx_id, it2.`trx_state` AS waiting_trx_status,it2.`trx_mysql_thread_id` AS waiting_thread,it2.`trx_query` AS waiting_