[关闭]
@JunQiu 2018-09-23T14:28:39.000000Z 字数 3517 阅读 1324

mysql mvcc 多版本并发控制技术

summary_2018/09 mysql


1、mysql mvcc 多版本并发控制技术

1.1、概念和用途

1.2、DB_TRX_ID、DB_ROLL_PTR

1.3、一致性视图readview

  1. ## 具体算法如下:
  2. 设该行的当前事务idtrx_idread view中最早的事务idtrx_id_min, 最迟的事务idtrx_id_max
  3. 1、如果trx_id< trx_id_min的话,那么表明该行记录所在的事务已经在本次新事务创建之前就提交了,所以该行记录的当前值是可见的。
  4. 2、如果trx_id>trx_id_max的话,那么表明该行记录所在的事务在本次新事务创建之后才开启,所以该行记录的当前值不可见。
  5. 3、如果trx_id_min<=trx_id<=trx_id_max,那么表明该行记录所在事务在本次新事务创建的时候处于活动状态,从trx_id_mintrx_id_max进行遍历,如果trx_id等于他们之中的某个事务id的话,那么不可见。
  6. //如果当前版本不可见则回滚再进行可见性判断,从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号的数据,将该可见行的值返回。
  7. TipsRRRC的一些区别
  8. 1、在RC事务隔离级别下,每次语句执行都关闭ReadView,然后重新创建一份ReadView
  9. 2、在RR事务隔离级别下,事务开始创建ReadView,一直到事务结束关闭
  10. ## 源代码
  11. 函数:read_view_sees_trx_id
  12. read_view中保存了当前全局的事务的范围:
  13. low_limit_id up_limit_id
  14. 1. 当行记录的事务ID小于当前系统的最小活动id,就是可见的。
  15.   if (trx_id < view->up_limit_id) {
  16.     return(TRUE);
  17.   }
  18. 2. 当行记录的事务ID大于当前系统的最大活动id(也就是尚未分配的下一个事务的id),就是不可见的。
  19.   if (trx_id >= view->low_limit_id) {
  20.     return(FALSE);
  21.   }
  22. 3. 当行记录的事务ID在活动范围之中时,判断是否在活动链表中,如果在就不可见,如果不在就是可见的。
  23.   for (i = 0; i < n_ids; i++) {
  24.     trx_id_t view_trx_id
  25.       = read_view_get_nth_trx_id(view, n_ids - i - 1);
  26.     if (trx_id <= view_trx_id) {
  27.     return(trx_id != view_trx_id);
  28.     }
  29.   }

1.5、 不同条件加锁的方式(比如主键、二级索引等)

1.6、 实际情况验证

  1. # delete 操作
  2. // 开启一个事务
  3. mysql> begin;
  4. Query OK, 0 rows affected (0.00 sec)
  5. mysql> select * from Persons;
  6. +------+
  7. | Id_P |
  8. +------+
  9. | 6 |
  10. | 6 |
  11. | 6 |
  12. | 6 |
  13. | 5 |
  14. +------+
  15. 5 rows in set (0.00 sec)
  16. ------ 开启另一个事务删除一条数据 ------
  17. mysql> DELETE FROM Persons where id_p=5;
  18. Query OK, 1 row affected (0.00 sec)
  19. ------ 开启另一个事务删除一条数据 ------
  20. mysql> select * from Persons;
  21. +------+
  22. | Id_P |
  23. +------+
  24. | 6 |
  25. | 6 |
  26. | 6 |
  27. | 6 |
  28. | 5 |
  29. +------+
  30. 5 rows in set (0.01 sec)
  31. mysql> commit;
  32. Query OK, 0 rows affected (0.00 sec)
  33. mysql> select * from Persons;
  34. +------+
  35. | Id_P |
  36. +------+
  37. | 6 |
  38. | 6 |
  39. | 6 |
  40. | 6 |
  41. +------+
  42. 4 rows in set (0.00 sec)
  43. 结论:对删除操作,不会立即删除,而会将删除标志位=1,直到commit后才会真正删除,但是会加X锁.
  44. # update 操作
  45. mysql> begin;
  46. Query OK, 0 rows affected (0.00 sec)
  47. mysql> update Persons set Id_P=66;
  48. Query OK, 4 rows affected (0.00 sec)
  49. Rows matched: 4 Changed: 4 Warnings: 0
  50. mysql> select * from Persons;
  51. +------+
  52. | Id_P |
  53. +------+
  54. | 66 |
  55. | 66 |
  56. | 66 |
  57. | 66 |
  58. +------+
  59. 4 rows in set (0.00 sec)
  60. ------ 开启另一个事务更新一条数据 ------
  61. mysql> update Persons set Id_P=77;
  62. // 阻塞,直到对当前行加锁的事务提交
  63. Query OK, 1 row affected (0.00 sec)
  64. ------ 开启另一个事务更新一条数据 ------
  65. mysql> commit;
  66. Query OK, 0 rows affected (0.00 sec)
  67. 结论:对于updatedelete等操作,会对对应行加锁,后面的事务想修改时会被阻塞,或者获取锁失败。
  1. mysql> begin;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> select * from Persons;
  4. +------+
  5. | Id_P |
  6. +------+
  7. | 2 |
  8. | 2 |
  9. +------+
  10. 2 rows in set (0.00 sec)
  11. ------ 开启另一个事务插入一条数据 ------
  12. mysql> INSERT INTO Persons VALUES (1);
  13. Query OK, 1 row affected (0.01 sec)
  14. ------ 开启另一个事务插入一条数据 ------
  15. mysql> select * from Persons;
  16. +------+
  17. | Id_P |
  18. +------+
  19. | 2 |
  20. | 2 |
  21. +------+
  22. 2 rows in set (0.00 sec)
  23. // 插入后在RR级别也避免了幻读,但更新并没有根据readview来判断,而是根据能否加锁来判断(此时事务版本号变为当前事务,可见)
  24. mysql> update Persons set Id_P=3 where Id_p=1;
  25. Query OK, 1 row affected (0.00 sec)
  26. Rows matched: 1 Changed: 1 Warnings: 0
  27. mysql> select * from Persons;
  28. +------+
  29. | Id_P |
  30. +------+
  31. | 2 |
  32. | 2 |
  33. | 3 |
  34. +------+
  35. 3 rows in set (0.00 sec)
  36. mysql> commit;
  37. Query OK, 0 rows affected (0.00 sec)

1.7、 比较好的参考资料

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注