MySQL'in LAST_INSERT_ID () işlevinin doğru olduğu garantili mi?


36

Bir sütunu INSERTolan bir tabloya tek bir satır AUTO_INCREMENTyaptığımda , bu satır için depolanan LAST_INSERT_ID()yeni AUTO_INCREMENTed ed değeri döndürmek için işlevi kullanmak istiyorum .

Pek çok Microsoft SQL Server geliştiricisi ve yöneticisi, SQL Server'daki ( SCOPE_IDENTITYve @@IDENTITY) eşdeğer işlevselliğin problemsiz olmadığının farkında değil .

MySQL dokümanlarının durumunu biliyorum:

Oluşturulan ID sunucuda bağlantı bazında tutulur . Bu, işlev tarafından belirli bir müşteriye döndürülen AUTO_INCREMENTdeğerin , o müşterinin bir AUTO_INCREMENTsütunu etkileyen en son ifade için üretilen ilk değer olduğu anlamına gelir . Bu değer, kendi değerlerini oluştursalar bile diğer müşterilerden etkilenemez . Bu davranış, her müşterinin, diğer müşterilerin faaliyeti için endişelenmeden ve kilitlere veya işlemlere ihtiyaç duymadan kendi kimliğini alabilmesini sağlar.AUTO_INCREMENT

(kaynak)

ve hatta söyleyecek kadar ileri gitmek:

Birden çok istemciden eşzamanlı olarak kullanmak LAST_INSERT_ID()ve AUTO_INCREMENTsütunlar mükemmel şekilde geçerlidir.

(kaynak)

LAST_INSERT_ID()Doğru değeri geri getirmemeye neden olabilecek bilinen herhangi bir risk veya senaryo var mı?

CentOS 5.5 x64 ve Fedora 16 x64 ve InnoDB motorunda MySQL 5.5 kullanıyorum.

Yanıtlar:


35

Kullanırken dikkat etmek istediğim bir çift uyarısı LAST_INSERT_ID:

  1. Tek sıralı eklerden bahsettiğini biliyorum. Ancak, çok satırlı ekler yaparken, LAST_INSERT_ID()eklenen ilk satırın değerini döndürür (sonuncuyu değil).

  2. Ekleme başarısız LAST_INSERT_ID()olursa tanımsız olur. Aynısı, işlemlerin otomatik olarak geri alınması için de geçerlidir (hatalardan dolayı).

  3. Eğer başarılı bir işlemde bir ekleme yapmak ve hala bir sorunu varsa ROLLBACK, LAST_INSERT_ID()o geri alma öncesinde olduğu gibi kalırdı.

  4. İfadeye dayalı çoğaltma kullanılırken AUTO_INCREMENTve kullanılırken birkaç uyarılar vardır LAST_INSERT_ID. İlki bir tetikleyici veya işlevde kullanıldığında. İkincisi, auto_increment sütununuzun bileşik bir birincil anahtarın parçası olduğu ve anahtardaki ilk sütun olmadığı daha az yaygın olan senaryodur.


7

DTest tarafından verilen cevabın 2 nolu noktasında daha fazla genişletmek için:

Kullandığım MySQL sürümlerinde, bir ekleme yapmayı planladığınız her kod bloğundan önce LAST_INSERT_ID değerini açık bir şekilde sıfırlamak iyi bir fikirdir .

Bu böyle yapılabilir:

-- initialize the LAST_INSERT_ID to some flag value:
SELECT LAST_INSERT_ID( some_flag_init_value_of_your_choice );
-- perform the insert  
INSERT INTO ttt (ccc) VALUES (vvv);
-- retrieve the id of the inserted row:  
SELECT LAST_INSERT_ID();

Yukarıdaki ifadeler dizisi gerçekleştirildikten sonra, ekin sonunda LAST_INSERT_ID'nin hala "some_flag_init_value_of_your_choice" olarak ayarlanıp ayarlanmadığını kontrol ederek etkisinin olup olmadığını bileceksiniz.

Aksi takdirde, aşağıdaki sorunlu durumla başlayabilirsiniz:

INSERT INTO ttt ( ccc ) VALUES ( 'a' );    -- assume this succeeds.
SELECT LAST_INSERT_ID();                   -- this will return the unique id of the new row with value 'a'.
INSERT INTO ttt ( ccc ) VALUES ( 'b' );    -- assume this FAILS.
SELECT LAST_INSERT_ID();                   -- this will STILL RETURN the unique id of the row with 'a'.

İkinci ekleme başarısız olduğundan , LAST_INSERT_ID numaralı ikinci çağrının ya NULL döndüreceğini ya da boş bir sonuç kümesi (sıfır satır) üretmesini bekliyor olabilirsiniz. Hala geçerli bir tamsayı tanımlayıcı döndürdüğü gerçeği, ikinci ekin girilmediğinde SUCCEEDED olduğunu düşünmenize yanlış yönlendirebilir.

Eğer LAST_INSERT_ID korumak ve sonraki başarısız insert ifadeleri hedefleyen bile son başarılı benzersiz kimliği tekrarlamak devam edeceğini göz önüne aldığımızda şeyler bile daha garip olsun farklı tablolar son başarılı benzersiz kimliği üretilen tablo daha. Başka bir deyişle, TA tablosuna ekleyip 5 kimliğini elde edersiniz, sonra TB'ye eklersiniz (ancak başarısız olur), ancak yine de 5 görürsünüz. Buna bağlı olarak, TA'da yeni bir satır oluşturduğunuzu düşünüyorsunuz 5 kimliğine ve TB'de 5 kimliğine sahip yeni bir sıraya sahipken gerçekte ya 5 kimliğine sahip TB'de herhangi bir satır yoktur ya da böyle bir satır yoktur ancak gerçekte sizin herhangi bir kodla ilgisi yoktur. koştu.


2
İlk önce last_insert_id(), bir sorgunun başarılı olup olmadığını yargılamak için varlığını kullanmamalıydınız. Ne de olsa başardığınızı bildiğiniz zaman ihtiyacınız olan değerleri tutan son eklenen Id.
Pacerier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.