Maison > Article > base de données > Comment implémenter le contrôle de concurrence multiversion MySQL MVVC
Le contrôle de concurrence multi-versions (MVCC) est une technologie de contrôle de concurrence. MVVC, qui implémente le contrôle de concurrence de base de données, est indissociable de la chaîne de versions dans le journal d'annulation, qui est réalisé en conservant plusieurs versions de lignes de données.
Pour faire simple, la transaction en cours interroge les lignes qui sont modifiées par une autre transaction (une lecture sale se produira si elle est lue à ce moment-là), sans verrouillage ni attente, mais en lisant la version historique du données. Réduisez le temps de réponse.
MVVC est implémenté via deux technologies : undo log et Read View.
L'implémentation de MVCC dans MySQL InnoDB vise principalement à améliorer les performances de concurrence des bases de données et à utiliser une meilleure façon de gérer même les conflits de lecture-écriture. s'il y a un conflit de lecture-écriture, aucune lecture simultanée verrouillable et non bloquante ne peut être obtenue, et cette lecture fait référence à la lecture d'instantané et non à la lecture actuelle. La lecture actuelle est en fait une opération de verrouillage.
Afin de garantir que l'enregistrement lu correspond aux données les plus récentes et d'éviter que d'autres transactions simultanées ne modifient l'enregistrement, l'enregistrement doit être ajouté lorsque lecture de Verrouillage.
La lecture verrouillée est appelée la lecture en cours, et l'ajout, la suppression et la modification de données doivent être lus en premier. Ce processus de lecture est également la lecture en cours.
SELECT * FROM t LOCK IN SHARE MODE; # 共享锁 SELECT * FROM t FOR UPDATE; # 排他锁 UPDATE SET t..
La lecture d'instantané est également appelée lecture cohérente, qui lit la version instantanée de la ligne de données. Dans MySQL, les instructions select ordinaires (instructions select sans for update ou lock en mode partage) utilisent la lecture d'instantanés par défaut sans verrouillage.
SELECT * FROM table WHERE ...
La raison en est que la lecture d'instantanés peut éviter les opérations de verrouillage et réduire les frais généraux.
Lorsque le niveau d'isolement de la transaction est en série, la lecture de l'instantané est inutile et se dégradera en lecture actuelle.
Niveau d'isolement :
Le niveau d'isolement par défaut dans MySQL est un RR en lecture répétable, qui peut être résolu Problème de lecture non reproductible, dans MySQL, un support spécial est fourni pour résoudre le problème de lecture fantôme.
Comment ça résout le problème de lecture fantôme ? Il existe deux manières :
Utiliser des verrous d'espacement et des verrous à clé temporaires pour résoudre le problème. En bref, c'est le verrouillage. Pendant cette période, les autres transactions ne peuvent pas insérer de données. 🎜🎜 #
# 🎜🎜#
Une transaction avec l'ID 8 crée une donnée, alors le schéma de principe de l'enregistrement est le suivant : #🎜 🎜#
Supposons que deux transactions avec les ID 10 et 20 mettent respectivement à jour cet enregistrement. Le processus est le suivant :
#🎜🎜 #. Affaires 10COMMIT; | |
UPDATE student SET name='Zhao Liu' WHERE id=1; | |
UPDATE student SET name= 'Qianqi' OÙ id=1; | # 🎜🎜# |
#🎜🎜 # 每个修改都会生成一个undo log日志,并与其他日志相互链接形成版本链,从而呈现出该条数据的图示 每个版本中还包含生成该版本时对应的事务id 。 四、Read View有了undo log就可以读取到记录的历史版本,那么在什么情况下,读取哪个版本的记录呢?这就用到了Read View,它帮我们解决了行的可见性问题。 读视图是指在使用MVCC机制进行快照读操作时产生的事务视图。这个视图是对当前数据库中所有活跃的、尚未提交的事务ID列表进行拍照的。 1.实现原理四种隔离级别里,读未提交和串行化是不会使用MVVC的,因为读未提交直接读取某个数据的最新数据即可,串行化是通过加锁来读的。 读已提交和可重复读都必须保证读到的数据都是其他事务提交了的,所以,其他事务修改了数据但是还未提交,我们不能够访问该数据,但可以通过MVVC机制读取该记录的历史版本,核心问题就是需要判断版本链中的哪条历史版本是当前事务可见的,这也是ReadView要解决的问题。 Read View包含4个比较重要的内容:
当事务对表中的记录作出修改时,才会分配一个事务ID,否则如果事务仅进行读取操作,则该事务的ID默认为0。
请注意,低限制事务ID不一定是trx_ids中的最大值,因为事务ID是按递增顺序分配的。例如,有三个事务的id分别为1、2、5,其中id为5的事务提交了。那么一个新的读事务在生成ReadView时, trx_ids就包括1和2,up_limit_id的值就是1,low_limit_id的值就是6。 2.Read View规则版本链 当某个事务有了Read View,访问某条记录时,需要按照下面的步骤判断该记录的哪个版本可见:
3.整体流程了解了这些概念之后,我们来看下当查询一条记录的时候,系统如何通过MVCC找到它:
在隔离级别为读已提交时,一个事务中的每一次SELECT查询都会重新获取一次Read View,而可重复读是第一SELECT操作才会生成Read View,之后的查询操作复用这一个。 导致这两种的差距是因为:可重复读要保证一个事务中相同的SELECT读取的内容是相同的。 五、举例1.READCOMMITTED隔离级别下 现在有两个事务id分别为10、20的事务在执行: -- id为10的事务 begin; update t set name='李四' where id=1; update t set name='王五' where id=1; -- id为20的事务 更新其他行的数据 此刻,表中id为1的记录得到的版本链表如下所示: 此时新来一个事务执行如下操作: begin; select * from t where id=1; -- 事务10、20未提交 查询到的结果为张三。 具体的过程如下:
接下来,再将id为10的事务进行commit提交。然后id为20的事务来更新记录: begin; -- id为20的事务 update t set name='赵六' where id=1; update t set name='钱七' where id=1; 此时版本链更新为: 再到刚才使用READ COMMITTED隔离级别的事务中继续查找这个id 为1的记录,得到的结果为name=王五的那条记录。执行过程如下:
注意:READ COMMITTED,每次读取数据前都生成一个新的ReadView。 2.REPEATABLE READ隔离级别下假如此时id为10的事务和id为20的事务正在修改,都未提交,修改内容和前面的一样,但是还未提交,此时当前事务做一个查询。 步骤为:
此时,id为10的记录提交事务。 当前事务又需要select id为1的记录,步骤为:
注意:REPEATABLE READ,每次读取都复用第一次生成的Read View 3.如何解决幻读假设现在有一条数据,id为1 当前活跃的事务有10和20。 此时当前事务启动了,执行如下SQL语句: begin; select * from student where id>=1; 在开始前生成Read View,内容如下:creator_trx_id=0,trx_ids= [10,20] , up_limit_id=10, low_limit_id=21。 由于id大于等于1的数据只有一个,且该数据的trx_id为8,小于up_limit_id,所以可以读取到。 在这之后id为10的事务新增了一行数据,增加了id为2的数据,且提交了。 此时当前线程继续查找id>=1的数据,因为是可重复读,复用刚刚的Read View。 得到两行数据,但是因为id为2的数据trx_id为10,该值在Read View的trx_ids中存在,所以该记录对当前事务不可见,所以最后查询到的数据只有一条记录。 如果当前事务再插入id为2的数据就插不进去,所以说MVVC只解决了一半的幻读问题。 |
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!