read commited 和 REPEATABLE read  

关于一致性读的问题。 参考 mysql 技术内幕--innodb 存储引擎

session 1

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2;

+------+

| id   |

+------+

|    1 |

+------+

1 row in set (0.00 sec)

同时到session2:

mysql> 

mysql> 

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2;

+------+

| id   |

+------+

|    1 |

+------+

1 row in set (0.00 sec)

mysql> update t2 set id=2;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> 

mysql> select * from t2;

+------+

| id   |

+------+

|    2 |

+------+

1 row in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.01 sec)

再回到session1:

如果是

mysql>  select @@tx_isolation;

+----------------+

| @@tx_isolation |

+----------------+

| READ-COMMITTED |

+----------------+

1 row in set (0.00 sec)

mysql> select * from t2;

+------+

| id   |

+------+

|    2 |

+------+

1 row in set (0.00 sec)

在session1 的同一个事物中,两次查询t2,会看到不通的结果,

如果是:

mysql> select @@tx_isolation;

+-----------------+

| @@tx_isolation  |

+-----------------+

| REPEATABLE-READ |

+-----------------+

1 row in set (0.00 sec)

在session 1 中,看到

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2;

+------+

| id   |

+------+

|    2 |

+------+

1 row in set (0.00 sec)

mysql> select * from t2;

+------+

| id   |

+------+

|    2 |

+------+

1 row in set (0.00 sec)

是同一个结果。 

这是由于mysql的一致性非锁定读 造成的。

如果读取的行正在备其他事物执行update或delete操作,这时读取操作不会因此去等待行上锁

的释放,innodb回去读一个快照数据。因为不需要等待访问的行上x锁的释放,所以称之为非锁定读。

快照数据是指该行 的之前版本的数据(可能有多个版本)。是通过undo断来实现的,undo是用

来在事物中回滚数据,因此快照数据没有额外开销。

在REPEATABLE read  下,快照读总是读取事物开始时的行版本数据;而在read commited下,

是读取最新一份快照,所以一个查询会看到不通的结果。