@JunQiu
2018-09-23T14:28:39.000000Z
字数 3517
阅读 1718
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,然后重新创建一份ReadView2、在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: 0mysql> 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: 0mysql> 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)
