dataiotech Labs
dbaguidedbaguideDBAdataxtoolsdataopsphere
[Teşhis]MySQL MySQL 8.0 / 8.4Advanced
5 dk okuma

MySQL Deadlock ERROR 1213: Grafiği Okuma ve Kalıcı Önleme

MySQL "Deadlock found when trying to get lock" — Neden Olur, Nasıl Kalıcı Çözülür?

Yazar / Standart:Kıdemli Veritabanı Mimarı & SRE (dataiotech Labs)
ERROR 1213 (40001): Deadlock found when trying to get lock
İlk 60 Saniye Teşhis Protokolü:

Hata mesajı semptomdur, kök neden değildir. Sunucuyu yeniden başlatmadan veya rastgele ayar değiştirmeden önce aşağıdaki "Nedeni ayırt eden tek sorgu"yu çalıştırarak gerçek senaryoyu netleştirin.

▸Belirti

plaintext
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Önce şunu netleştirelim: deadlock bir hata değil, InnoDB'nin koruma mekanizmasıdır. İki işlem birbirinin kilidini beklerken döngü oluşur; InnoDB döngüyü tespit eder, kurban seçer ve o işlemi tamamen geri alır. Bu yüzden doğru refleks "deadlock'ı engellemek" değil, "deadlock'a dayanıklı uygulama yazmak" ve ardından oluşum sıklığını azaltmaktır.


▸Grafiği bulma

1. Anlık kayıt:

sql
SHOW ENGINE INNODB STATUS\G

Çıktıda LATEST DETECTED DEADLOCK bölümüne bakın. Bu yalnızca son deadlock'ı gösterir.

2. Kalıcı kayıt (bunu açın):

sql
SET GLOBAL innodb_print_all_deadlocks = ON;

Artık her deadlock, MySQL hata günlüğüne grafiğiyle birlikte yazılır. Maliyeti ihmal edilebilir, teşhis değeri yüksektir.

3. Bekleyen kilitleri canlı görme:

sql
SELECT w.requesting_engine_transaction_id AS bekleyen, w.blocking_engine_transaction_id AS bloklayan, r.trx_query AS bekleyen_sorgu, b.trx_query AS bloklayan_sorgu, b.trx_mysql_thread_id AS bloklayan_thread FROM performance_schema.data_lock_waits w LEFT JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_engine_transaction_id LEFT JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_engine_transaction_id;

▸En sık üç neden

1. Ters erişim sırası. Bir işlem A sonra B tablosuna, diğeri B sonra A'ya dokunuyorsa deadlock kaçınılmazdır. Uygulamada sabit bir erişim sırası belirleyin. Kodu düzeltmeden yapılan her parametre değişikliği geçicidir.

2. İndekssiz `WHERE` ve gap lock. REPEATABLE READ izolasyon seviyesinde, indekssiz bir UPDATE/DELETE taranan tüm aralığa gap lock koyar. İki işlem farklı satırları güncellese bile birbirini bekler. Kontrol:

sql
EXPLAIN UPDATE hesaplar SET bakiye = bakiye - 10 WHERE musteri_no = 42;

type: ALL ya da rows çok yüksekse, önce indeks ekleyin. Yüksek eşzamanlı OLTP iş yüklerinde READ COMMITTED'a geçmek gap lock kaynaklı deadlock'ların büyük kısmını ortadan kaldırır:

sql
SELECT @@transaction_isolation;

3. Uzun işlemler ve toplu güncellemeler. Tek bir UPDATE ile 500.000 satır güncellemek, kilitleri saniyeler boyunca tutar. Toplu işlemleri parçalayın:

sql
UPDATE siparisler SET durum = 'arsiv' WHERE durum = 'tamamlandi' AND id BETWEEN 1 AND 10000; -- her partiden sonra COMMIT

▸Uygulama tarafında retry tasarımı

Deadlock kurbanı olan işlem tamamen geri alınır; uygulama bunu beklenen bir durum olarak ele almalıdır.

  • •Retry yalnızca 1213 (deadlock) ve 1205 (lock wait timeout) için yapılmalı.
  • •İşlem idempotent olmalı; aksi halde retry çift kayıt üretir.
  • •Retry sayısı sınırlı (3-5), bekleme süresi artan (jitter'lı) olmalı.
  • •Retry, deadlock'ın oluştuğu *tüm* transaction'ı kapsamalı.

▸İlgili Mühendislik Rehberleri ve İç Linkler

MySQL Diğer Üretim Rehberleri

Aynı veritabanı motoruna ait doğrulanmış diğer içerikler.

Tümünü Gör