Dieser Artikel vermittelt Ihnen relevantes Wissen über MySQL-Sperren und -Deadlocks. Ich hoffe, dass er für alle hilfreich ist.
Concept
spricht darüber, wie InnoDB
das Sperr- und Freigabeverhalten von Zeilensperren handhabt. 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
Transaktionsprozesses
, wenn ein Datensatz basierend auf dem Primärschlüssel gelöscht wird, wird 🎜sofort🎜eine exklusive Sperre hinzugefügt, wodurch die 🎜Sperrphase🎜 abgeschlossen wird. 🎜🎜Wenn der Löschvorgang abgeschlossen ist, wird die Sperre nicht sofort aufgehoben. Die Sperre wird erst dann freigegeben, wenn die Transaktion festgeschrieben ist. 🎜🎜Transaktion A🎜 | 🎜Transaktion B🎜 |
---|---|
begin; update t set k=k+1 where id=1; update t set k=k+1 where id=2; |
|
td > |
begin; update t set k=k+2 where id=1; |
commit |
Transaktion B🎜 wird blockiert, weil die Daten von 🎜<code>id=1
🎜 durch 🎜Transaktion A
🎜 gesperrt sind, weil 🎜Transaktion B
🎜Sie müssen die Sperre erhalten, bevor Sie mit dem nächsten Schritt fortfahren können. 🎜🎜🎜Das obige Problem scheint kein großes Problem zu sein, aber wenn es sich nicht nur um Transaktion B
, sondern auch um Transaktion C
, Transaktion D
handelt > Wenn Sie lange warten und dasselbe wie bei Transaktion B
tun, wird das Problem groß und es werden mehr Threads blockiert. [Empfohlenes Lernen: MySQL-Video-Tutorial]🎜id=1
in der obigen Transaktion A code> Beispiel. Es hat nichts mit der Ausführung des zweiten Satzes zu tun, aber es ist eine Anweisung, die leicht zu einer Blockierung führen kann, da diese Datenzeile auch in <code>Transaktion B
gesperrt werden muss (häufig verwendet). in verschiedenen Transaktionen) verwendet, wie z. B. der Kontostand des Inkasso- und Zahlungskontos des Unternehmens, d. h. **Hotline**
), aber die Sperre wurde zu Beginn der Transaktion erhalten. 🎜🎜Im Wesentlichen verkürzt es die Zeit zwischen dem Erfassen der Sperre und der Freigabe der Sperre. Das heißt, die Haltezeit der Sperre wird verkürzt, wodurch die durch die Sperre verursachte Blockierung verringert wird. 🎜🎜Deadlock🎜🎜🎜Konzept🎜🎜🎜Zwei Threads warten aufeinander, um Ressourcen freizugeben. 🎜🎜In zwei Transaktionen A und B. 🎜Transaktion A
hat die Sperre von Ressource A
erhalten. 🎜Transaktion B
hat die Sperre von Ressource B
erhalten. 🎜Transaktion A
erhält die Sperre von Ressource B
. 🎜Transaktion B
erhält die Sperre von Ressource A
. 🎜InnoDB
gibt es eine Wartezeitkonfiguration für die Sperrenerfassung. Wenn diese Zeit überschritten wird, wird eine Ausnahme ausgelöst 50Sekunden. Im Allgemeinen ist es inakzeptabel, eine Schnittstelle zu haben, deren Antwort 50
Sekunden dauert. innodb_lock_wait_timeout
. 🎜🎜Reicht es aus, diese Konfigurationszeit kürzer einzustellen? Zum Beispiel 1
Sekunden? 🎜🎜Dies sollte nicht möglich sein, da es Ihr normales Geschäft beeinträchtigen kann. Möglicherweise führt Ihr Unternehmen dazu, dass die Ausführungszeit Ihrer Transaktion relativ lang ist und 1
Sekunden überschreitet. Wenn diese Zeit überschritten wird, wird eine Ausnahme ausgelöst und Ihr normaler Geschäftsbetrieb wird beeinträchtigt. 🎜🎜🎜So gehen Sie mit den oben genannten Problemen um🎜🎜🎜In InnoDB
gibt es auch eine Konfiguration zur automatischen Erkennung und Behandlung von Deadlocks. Es ist standardmäßig aktiviert, obwohl es das Problem lösen kann, verbraucht es viel CPU
. 🎜🎜Das Prinzip besteht darin, dass, wenn eine Transaktion gesperrt werden soll, erkannt wird, ob andere gleichzeitige Threads diese Ressource gesperrt haben. Wenn festgestellt wird, dass ein bestimmter Thread A
vorhanden ist, wird dies auch erkannt Ob die Abhängigkeiten von Thread A
durch andere gleichzeitige Threads usw. gesperrt sind, bestimmt letztendlich, ob diese Sperren einen Deadlock bilden. 🎜🎜Es ist ersichtlich, dass die Erkennungskosten umso höher sind, je mehr Threads vorhanden sind. innodb_deadlock_detect
. 🎜🎜Dies stellt nur die Verarbeitung und Zusammenfassung dieses Problems basierend auf persönlichen aktuellen Erkenntnissen dar: 🎜🎜1 Deaktivieren Sie die Deadlock-Erkennung und verkürzen Sie die Konfiguration der Sperrhaltezeit auf die geschätzte maximale Zeit, die normalerweise 15 Sekunden, nach <code>15
Sekunden ist ein Wiederholungsmechanismus erforderlich. 🎜🎜2. Aktivieren Sie die Deadlock-Erkennung, steuern Sie die Anzahl gleichzeitiger Verbindungen auf der Anwendungsebene, verwenden Sie den Verbindungspool, um die Anzahl der Mysql
-Verbindungen zu steuern, und begrenzen Sie die maximale Anzahl von Mysql Verbindungen auf der Serviceebene. 🎜🎜Das Obige ist eine Zusammenfassung der Erkenntnisse darüber, wie Sie die Auswirkungen von Zeilensperren auf die Leistung reduzieren können. 🎜
Das obige ist der detaillierte Inhalt vonLassen Sie uns über die zweiphasige Sperre und den Deadlock von MySQL sprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!