- 论坛徽章:
- 0
|
本帖最后由 justlooks 于 2010-08-26 14:18 编辑
首先是来自手册的一致性读的定义:
A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time
一致读就是innodb使用MVCC机制把数据库某一点的快照提供给一个查询
The query sees the changes made by transactions that committed before that point of time, and no changes made by later or uncommitted transactions.
该查询能够看到在这个点之前提交的事务所做的所有改变,但是看不到之后开始的事务,或者是在这个时间点还未提交的事务所做的改变
innobase使用read view来实现这个一致读,read view和trx是紧密联系的,通过view_list域把自己连到trx_sys上,而每个read view都有个创建它的trx,用creator_trx_id字段标记
来看下read view的数据结构
- struct read_view_struct{
- ulint type;
- dulint undo_no;
- dulint low_limit_no; #这个不是很清楚
- dulint low_limit_id;
- dulint up_limit_id;
- ulint n_trx_ids;
- dulint* trx_ids;
- dulint creator_trx_id;
- UT_LIST_NODE_T(read_view_t) view_list;
- }
复制代码 那么从read view的创建代码(read_view_open_now调用)并结合定义来分析以上字段的意义
- #首先会在trx_sys系统结构中统计所有当前没有提交的事务
- view = read_view_create_low(UT_LIST_GET_LEN(trx_sys->trx_list), heap)
- #那么对于该view创建点之后的新事务,该read view是无法看到其数据变化的,read view用low_limit_id来标记这个时间点,也就是说凡是trx id超过这个值的就属于将来的事务
- view->low_limit_no = trx_sys->max_trx_id;
- view->low_limit_id = view->low_limit_no;
- #那么自然所有这个创建时间中活跃的事务也是无法被该view看到的,除了read view的创建者(注意这个例外,会导致奇怪的现象)
- n = 0;
- trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
- while (trx) {
- if (ut_dulint_cmp(trx->id, cr_trx_id) != 0
- && (trx->conc_state == TRX_ACTIVE
- || trx->conc_state == TRX_PREPARED)) {
- .......
- trx = UT_LIST_GET_NEXT(trx_list, trx);
- }
- #而如何描述过去呢?read view用up_limit_id描述过去,也就是当trx id小于这个值都是过去commit的事务
- if (n > 0) {
- view->up_limit_id = read_view_get_nth_trx_id(view, n - 1); #因为这个数组是来自trx list的,而trx list是开头是最新的事务,所以这个就是最老的未commit的事务
- } else {
- view->up_limit_id = view->low_limit_id;
- }
- #VIEW list也是从新到旧排列的
- UT_LIST_ADD_FIRST(view_list, trx_sys->view_list, view);
复制代码 下面是一致读的判定代码,对照上面的说明应该很清楚了,在read_view_sees_trx_id调用中
- if (ut_dulint_cmp(trx_id, view->up_limit_id) < 0) {
- return(TRUE);
- }
- if (ut_dulint_cmp(trx_id, view->low_limit_id) >= 0) {
- return(FALSE);
- }
- n_ids = view->n_trx_ids;
- for (i = 0; i < n_ids; i++) {
- cmp = ut_dulint_cmp(
- trx_id,
- read_view_get_nth_trx_id(view, n_ids - i - 1));
- if (cmp <= 0) {
- return(cmp < 0);
- }
- }
- return(TRUE);
复制代码 那么再来看下上面提到的奇怪的现象,先来看演示
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`name` char(10) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
S1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
S2
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update t1 set id=id+200 where name='bbb';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
S1
mysql> select * from t1;
+----+------+
| id | name |
+----+------+
| 1 | aaa |
| 22 | bbb |
+----+------+
2 rows in set (0.00 sec)
S2
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
S1
mysql> update t1 set id=id+20 where name='bbb';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1;
+-----+------+
| id | name |
+-----+------+
| 1 | aaa |
| 22 | bbb |
| 242 | bbb |
+-----+------+
3 rows in set (0.00 sec) |
评分
-
查看全部评分
|