@JunQiu
2018-09-23T22:28:39.000000Z
字数 3517
阅读 1425
summary_2018/09
mysql
## 具体算法如下:
设该行的当前事务id为trx_id,read view中最早的事务id为trx_id_min, 最迟的事务id为trx_id_max。
1、如果trx_id< trx_id_min的话,那么表明该行记录所在的事务已经在本次新事务创建之前就提交了,所以该行记录的当前值是可见的。
2、如果trx_id>trx_id_max的话,那么表明该行记录所在的事务在本次新事务创建之后才开启,所以该行记录的当前值不可见。
3、如果trx_id_min<=trx_id<=trx_id_max,那么表明该行记录所在事务在本次新事务创建的时候处于活动状态,从trx_id_min到trx_id_max进行遍历,如果trx_id等于他们之中的某个事务id的话,那么不可见。
//如果当前版本不可见则回滚再进行可见性判断,从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号的数据,将该可见行的值返回。
Tips:RR和RC的一些区别
1、在RC事务隔离级别下,每次语句执行都关闭ReadView,然后重新创建一份ReadView
2、在RR事务隔离级别下,事务开始创建ReadView,一直到事务结束关闭
## 源代码
函数:read_view_sees_trx_id。
read_view中保存了当前全局的事务的范围:
【low_limit_id, up_limit_id】
1. 当行记录的事务ID小于当前系统的最小活动id,就是可见的。
if (trx_id < view->up_limit_id) {
return(TRUE);
}
2. 当行记录的事务ID大于当前系统的最大活动id(也就是尚未分配的下一个事务的id),就是不可见的。
if (trx_id >= view->low_limit_id) {
return(FALSE);
}
3. 当行记录的事务ID在活动范围之中时,判断是否在活动链表中,如果在就不可见,如果不在就是可见的。
for (i = 0; i < n_ids; i++) {
trx_id_t view_trx_id
= read_view_get_nth_trx_id(view, n_ids - i - 1);
if (trx_id <= view_trx_id) {
return(trx_id != view_trx_id);
}
}
# delete 操作
// 开启一个事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 6 |
| 6 |
| 6 |
| 6 |
| 5 |
+------+
5 rows in set (0.00 sec)
------ 开启另一个事务删除一条数据 ------
mysql> DELETE FROM Persons where id_p=5;
Query OK, 1 row affected (0.00 sec)
------ 开启另一个事务删除一条数据 ------
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 6 |
| 6 |
| 6 |
| 6 |
| 5 |
+------+
5 rows in set (0.01 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 6 |
| 6 |
| 6 |
| 6 |
+------+
4 rows in set (0.00 sec)
结论:对删除操作,不会立即删除,而会将删除标志位=1,直到commit后才会真正删除,但是会加X锁.
# update 操作
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update Persons set Id_P=66;
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4 Changed: 4 Warnings: 0
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 66 |
| 66 |
| 66 |
| 66 |
+------+
4 rows in set (0.00 sec)
------ 开启另一个事务更新一条数据 ------
mysql> update Persons set Id_P=77;
// 阻塞,直到对当前行加锁的事务提交
Query OK, 1 row affected (0.00 sec)
------ 开启另一个事务更新一条数据 ------
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
结论:对于update、delete等操作,会对对应行加锁,后面的事务想修改时会被阻塞,或者获取锁失败。
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 2 |
| 2 |
+------+
2 rows in set (0.00 sec)
------ 开启另一个事务插入一条数据 ------
mysql> INSERT INTO Persons VALUES (1);
Query OK, 1 row affected (0.01 sec)
------ 开启另一个事务插入一条数据 ------
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 2 |
| 2 |
+------+
2 rows in set (0.00 sec)
// 插入后在RR级别也避免了幻读,但更新并没有根据readview来判断,而是根据能否加锁来判断(此时事务版本号变为当前事务,可见)
mysql> update Persons set Id_P=3 where Id_p=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from Persons;
+------+
| Id_P |
+------+
| 2 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)