2011-01-31 19 views
5

ile geri dönüş işlemleri MySQL/5.1 altındaki işlemleri kullanan bir PHP/5.2 tabanlı uygulamasına sahibim, böylece bir hata durumu karşılanırsa birden çok eki geri alabilir. Farklı türde öğeler eklemek için farklı yeniden kullanılabilir işlevlerim var. Çok uzak çok iyi.LOCK TABLOLAR

Şimdi bazı ek parçalar için masa kilidini kullanmam gerekiyor. Resmi kılavuzun önerdiği gibi, START TRANSACTION yerine SET autocommit=0 kullanıyorum, dolayısıyla LOCK TABLES örtük bir taahhüt vermiyor. Ve belgelendiği gibi, tablolar kilidini örtülü herhangi bir etkin işlem taahhüt:

Ve burada sorun yatıyor: Ben sadece UNLOCK TABLES önlemek, eğer LOCK TABLES ikinci çağrı bekleyen değişiklikleri kaydeder olur!

Tek bir ifade ile tüm gerekli LOCK TABLES gerçekleştirmek için görünür. Bu bir ana karanlik kabusu.

Bu sorunun mantıklı bir çözümü var mı?

DROP TABLE IF EXISTS test; 

CREATE TABLE test (
    test_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    random_number INT(10) UNSIGNED NOT NULL, 
    PRIMARY KEY (test_id) 
) 
COLLATE='utf8_spanish_ci' 
ENGINE=InnoDB; 


-- No table locking: everything's fine 
START TRANSACTION; 
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND())); 
SELECT * FROM TEST ORDER BY test_id; 
ROLLBACK; 
SELECT * FROM TEST ORDER BY test_id; 



-- Table locking: everything's fine if I avoid START TRANSACTION 
SET autocommit=0; 
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND())); 
SELECT * FROM TEST ORDER BY test_id; 
ROLLBACK; 
SELECT * FROM TEST ORDER BY test_id; 
SET autocommit=1; 



-- Table locking: I cannot nest LOCK/UNLOCK blocks 
SET autocommit=0; 
LOCK TABLES test WRITE; 
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND())); 
SELECT * FROM TEST ORDER BY test_id; 
ROLLBACK; 
UNLOCK TABLES; -- Implicit commit 
SELECT * FROM TEST ORDER BY test_id; 
SET autocommit=1; 


-- Table locking: I cannot chain LOCK calls ether 
SET autocommit=0; 
LOCK TABLES test WRITE; 
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND())); 
SELECT * FROM TEST ORDER BY test_id; 
-- UNLOCK TABLES; 
LOCK TABLES test WRITE; -- Implicit commit 
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND())); 
SELECT * FROM TEST ORDER BY test_id; 
-- UNLOCK TABLES; 
ROLLBACK; 
SELECT * FROM TEST ORDER BY test_id; 
SET autocommit=1; 
+0

Neden kilitleme ihtiyacı mı? Asıl sorun nedir? –

+0

Sadece bir işlemin geçerli yıl için bir sıra numarası kullanabildiğinden ve sırada boşluk bırakılmadığından emin olmak için kilitlemeye ihtiyacım var. Asıl sorun, MySQL'in işlem onaylamayan bir özelliği kullanmaya çalıştığınızda otomatik olarak onaylanmamış veri kümelerini otomatik olarak çalıştırmasıdır. –

+1

SELECT .... 'i UPDATE İÇİN Kullanamazsınız; ? İşlemlerde gayet iyi çalışıyor, hiç sorun değil. Dizi için tek bir kayıt kullanın ve bu kaydı her seferinde güncelleyin. –

cevap

4

Görünüşe LOCK TABLES işlemler ile iyi oynamak çözülemez:

İşte küçük bir test senaryo. Bir geçici çözüm, SELECT .... FOR UPDATE ile değiştirmektir. Herhangi özel bir sözdizimi gerekmez (normal START TRANSACTION kullanabilirsiniz) ve beklendiği gibi çalışır:

START TRANSACTION; 
SELECT COUNT(*) FROM foo FOR UPDATE; -- Lock issued 
INSERT INTO foo (foo_name) VALUES ('John'); 
SELECT COUNT(*) FROM bar FOR UPDATE; -- Lock issued, no side effects 
ROLLBACK; -- Rollback works as expected 

COUNT(*) sadece bir örnek olduğunu unutmayın, normalde aslında gerek veri getirmek için SEÇ deyimi kullanabilirsiniz ;-)

(Bu bilgiler Frank Heikens tarafından sağlandı.)

+2

Lütfen SEÇİM ... SEÇİMİ için hala diğer veritabanı oturumlarının tablodan okunmasına izin verdiğini unutmayın. Umarım bu işleve güvenmeden önce birilerine yardım eder. –