Cet article vous apporte des connaissances pertinentes sur les verrous MySQL. Il présente principalement les verrous et les blocages MySQL en deux étapes. J'espère qu'il sera utile à tout le monde.
Concept
explique comment InnoDB
gère le comportement de verrouillage et de déverrouillage des lignes. InnoDB
如何处理行锁的上锁,释放锁的行为。
在事务使用过程中,对记录以主键为条件删改时,会立刻加上排他锁,这完成了上锁阶段。
当删改动作完成后,这个锁并不会立即释放,需要等至事务提交时,才会释放锁。
事务 A | 事务 B |
---|---|
begin; update t set k=k+1 where id=1; update t set k=k+1 where id=2; |
|
begin; update t set k=k+2 where id=1; |
|
commit; |
根据两阶段锁协议,事务 B
将会因为id=1
的数据被事务 A
上了锁,而阻塞,因为事务 B
需要拿到锁后才能进行下一步操作。
上述这个问题,可能看似问题不大,但是如果不止是事务 B
,还有事务 C
,事务 D
,等等很多,做的是跟事务 B
一样的事,问题就大了,被阻塞的线程就会多了起来。【推荐学习:MySQL视频教程】
我们应该尽量将可能会引起阻塞的语句,放到事务的最后面操作,例如上述事务 A
例子中的id=1
的语句,它和第二句的执行并没有什么关联关系,可是它是容易引起阻塞的语句,因为在事务 B
中也要对这一行数据做锁操作(在各类事务中频繁使用的,如公司的收付款账号余额记录,即**热点行**
),但是却在事务一开始就拿到锁了。
本质上,是缩短了拿锁时间和释放锁之间的时间。即持有锁的时间缩短,以此减少锁引起的阻塞。
概念
两个线程,互相在等待对方释放资源。
在两个事务A,B中。
事务 A
拿到了资源 A
的锁。
事务 B
拿到了资源 B
的锁。
事务 A
去拿资源 B
的锁。
事务 B
去拿资源 A
的锁。
很明显,步骤 3,4中,事务 A,B 都想去拿锁,但是又都拿不到,因为对方都还没有释放该资源的锁。这种现象就是死锁。
引发的问题-死锁
在InnoDB
中,有一个拿锁的等待时间配置,超过这个时间就会抛出异常,这个时间默认是50
秒。通常来说,有一个接口需要50
秒后才响应是不可接受的。innodb_lock_wait_timeout
。
那是不是把这个配置时间设置短一点就行了?比如1
秒?
应该是不可以的,因为可能会影响到你的正常业务,或许你的业务导致你的事务执行时间本身就比较长,超过1
秒。超出这个时间会抛出异常,你的正常业务就被影响了。
那该如何处理上述问题
在InnoDB
中,还有一个自动检测死锁并处理的配置。它是默认开启的,在极端情况下,虽然能处理问题,但是对CPU
消耗特别大。
它原理是在事务中即将要上锁的时候,会去检测其他并发线程,有没有将此资源锁住,如果检测到某个线程A
有,然后再会去检测线程A
的依赖有没有被其他并发线程锁住,如此循环往复,最终判断这些锁会不会形成死锁。
可以看出,线程越多,检测成本就越大。innodb_deadlock_detect
。
仅代表个人当前的学习做出的对此问题的处理和总结:
1.关闭死锁检测,将拿锁时间配置缩短至预估的最高时间,通常不会超过15
秒,超过15
秒后,需要有重试机制。
2.开启死锁检测,在应用层控制并发连接数,使用连接池控制Mysql
的连接数,在服务层限制Mysql
processus de transaction
, lorsqu'un enregistrement est supprimé en fonction de la clé primaire, un verrou exclusif sera 🎜immédiatement🎜ajouté, ce qui complète l'étape de 🎜verrouillage🎜. 🎜🎜Lorsque l'action de suppression est terminée, le verrou ne sera pas libéré immédiatement. Il 🎜libérera le verrou🎜 jusqu'à ce que la transaction soit validée. 🎜🎜Transaction A🎜 | 🎜Transaction B🎜 |
---|---|
begin; mettre à jour t set k=k+1 où id=1; mettre à jour t définir k=k+1 où id=2 ; |
|
td > |
begin; mettre à jour t définir k=k+2 où id=1; |
commit |
Transaction B🎜 sera bloqué car les données de 🎜<code>id=1
🎜 sont verrouillées par 🎜Transaction A
🎜, car 🎜Transaction B
🎜Vous devez obtenir le cadenas avant de passer à l'étape suivante. 🎜🎜🎜Le problème ci-dessus peut ne pas sembler être un gros problème, mais s'il ne s'agit pas seulement de la Transaction B
, mais aussi de la Transaction C
, de la Transaction D
, Si vous attendez beaucoup et faites la même chose que Transaction B
, le problème sera gros et davantage de threads seront bloqués. [Apprentissage recommandé : Tutoriel vidéo MySQL]🎜id=1
dans la Transaction A code> exemple. Cela n'a rien à voir avec l'exécution de la deuxième phrase, mais c'est une instruction qui peut facilement provoquer un blocage, car cette ligne de données doit également être verrouillée dans la <code>Transaction B
(fréquemment utilisée). dans diverses transactions) utilisé, comme le relevé du solde du compte d'encaissement et de paiement de l'entreprise, c'est-à-dire **hot line**
), mais le verrou a été obtenu au début de la transaction. 🎜🎜Essentiellement, cela réduit le temps entre l'acquisition et le déverrouillage du verrou. C'est-à-dire que la durée pendant laquelle le verrou est maintenu est raccourcie, réduisant ainsi le blocage provoqué par le verrou. 🎜🎜Deadlock🎜🎜🎜Concept🎜🎜🎜Deux fils s'attendent pour libérer des ressources. 🎜🎜En deux transactions A et B. 🎜Transaction A
a obtenu le verrou de la Ressource A
. 🎜Transaction B
a obtenu le verrou de la Ressource B
. 🎜Transaction A
obtient le verrou de la Ressource B
. 🎜Transaction B
obtient le verrou de la Ressource A
. 🎜InnoDB
, il existe une configuration de temps d'attente pour l'acquisition du verrou. Si ce délai est dépassé, une exception sera levée. Le temps par défaut est . 50secondes. De manière générale, il est inacceptable d'avoir une interface qui met <code>50
secondes à répondre. innodb_lock_wait_timeout
. 🎜🎜Est-il suffisant de raccourcir ce temps de configuration ? Par exemple, 1
secondes ? 🎜🎜Cela ne devrait pas être possible, car cela pourrait affecter votre activité normale. Peut-être que votre entreprise rend le temps d'exécution de votre transaction relativement long, dépassant 1
secondes. Si ce délai est dépassé, une exception sera levée et votre activité normale sera affectée. 🎜🎜🎜Alors, comment gérer les problèmes ci-dessus🎜🎜🎜Dans InnoDB
, il existe également une configuration pour détecter et gérer automatiquement les blocages. Il est activé par défaut, dans les cas extrêmes, bien qu'il puisse résoudre le problème, il consomme beaucoup de CPU
. 🎜🎜Le principe est que lorsqu'une transaction est sur le point d'être verrouillée, elle détectera si d'autres threads simultanés ont verrouillé cette ressource. S'il est détecté qu'un certain thread A
l'a fait, il détectera alors si. les dépendances du Thread A
sont verrouillées par d'autres threads concurrents, et ainsi de suite, détermineront éventuellement si ces verrous formeront une impasse. 🎜🎜On constate que plus il y a de threads, plus le coût de détection est élevé. innodb_deadlock_detect
. 🎜🎜Cela représente uniquement le traitement et le résumé de ce problème sur la base de l'apprentissage personnel actuel : 🎜🎜1. Désactivez la détection de blocage et réduisez la configuration du temps de maintien du verrou à la durée maximale estimée, qui ne dépassera généralement pas 15<.> secondes, après <code>15
secondes, un mécanisme de nouvelle tentative est requis. 🎜🎜2. Activez la détection des blocages, contrôlez le nombre de connexions simultanées au niveau de la couche application, utilisez le pool de connexions pour contrôler le nombre de connexions Mysql
et limitez le nombre maximum de connexions Mysql<.> connexions au niveau de la couche de service. 🎜🎜Ce qui précède est un résumé de la façon de réduire l'impact sur les performances des verrous de ligne. 🎜</.>
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!