İstediğiniz şey , bir işlem bağlamında GÜNCELLEME İÇİN SEÇ ... 'i seçmektir . GÜNCELLEME SEÇ, tıpkı GÜNCELLEME yürütüyormuşsunuz gibi seçilen satırlara özel bir kilit koyar. Ayrıca, yalıtım düzeyinin açıkça ne ayarlandığına bakılmaksızın, ÖĞRENMİŞ TALİMATI yalıtım düzeyinde çalışır. SELECT ... FOR UPDATE'in eşzamanlılık için çok kötü olduğunu ve yalnızca kesinlikle gerekli olduğunda kullanılması gerektiğini unutmayın. Ayrıca, insanlar kesip yapıştırdıkça bir kod tabanında çoğalma eğilimi gösterir.
Sakila veritabanından FOR UPDATE sorgularının bazı davranışlarını gösteren örnek bir oturum.
İlk olarak, kristal netliğinde işlem yalıtım seviyesini REPEATABLE READ olarak ayarlayın. InnoDB için varsayılan yalıtım seviyesi olduğundan bu normalde gereksizdir:
session1> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
session1> BEGIN;
session1> SELECT first_name, last_name FROM customer WHERE customer_id = 3;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| LINDA | WILLIAMS |
+------------+-----------+
1 row in set (0.00 sec)
Diğer oturumda bu satırı güncelleyin. Linda evlendi ve adını değiştirdi:
session2> UPDATE customer SET last_name = 'BROWN' WHERE customer_id = 3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
1. oturumda, REPEATABLE READ'deyken Linda hala LINDA WILLIAMS:
session1> SELECT first_name, last_name FROM customer WHERE customer_id = 3;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| LINDA | WILLIAMS |
+------------+-----------+
1 row in set (0.00 sec)
Ama şimdi, bu satıra özel erişim istiyoruz, bu yüzden satırda FORDDATE'i çağırıyoruz. Şimdi bu işlemin dışındaki session2 sürümünde güncellenen satırın en son sürümünü aldığımıza dikkat edin. Bu TEKRARLANABİLİR OKUMA DEĞİL, OKUYAN OKULDU
session1> SELECT first_name, last_name FROM customer WHERE customer_id = 3 FOR UPDATE;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| LINDA | BROWN |
+------------+-----------+
1 row in set (0.00 sec)
Oturum1'de ayarlanan kilidi test edelim. Session2'nin satırı güncelleyemeyeceğini unutmayın.
session2> UPDATE customer SET last_name = 'SMITH' WHERE customer_id = 3;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Ama yine de seçebiliriz
session2> SELECT c.customer_id, c.first_name, c.last_name, a.address_id, a.address FROM customer c JOIN address a USING (address_id) WHERE c.customer_id = 3;
+-------------+------------+-----------+------------+-------------------+
| customer_id | first_name | last_name | address_id | address |
+-------------+------------+-----------+------------+-------------------+
| 3 | LINDA | BROWN | 7 | 692 Joliet Street |
+-------------+------------+-----------+------------+-------------------+
1 row in set (0.00 sec)
Ve yine de yabancı anahtar ilişkisi olan bir çocuk tablosunu güncelleyebiliriz
session2> UPDATE address SET address = '5 Main Street' WHERE address_id = 7;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
session1> COMMIT;
Bir başka yan etki, bir kilitlenmeye neden olma olasılığınızı büyük ölçüde artırmanızdır.
Özel durumunuzda, muhtemelen:
BEGIN;
SELECT id FROM `items` WHERE `status`='pending' LIMIT 1 FOR UPDATE;
-- do some other stuff
UPDATE `items` SET `status`='working', `updated`=NOW() WHERE `id`=<selected id>;
COMMIT;
"Başka şeyler yapın" parçası gereksizse ve aslında satır hakkında bilgi tutmanız gerekmiyorsa, GÜNCELLEME SEÇİN gereksiz ve israflıdır ve bunun yerine bir güncelleme çalıştırabilirsiniz:
UPDATE `items` SET `status`='working', `updated`=NOW() WHERE `status`='pending' LIMIT 1;
Umarım bu biraz mantıklıdır.
items
WHEREstatus
= 'bekleyen' LIMIT 1 FOR UPDATE; ve ikisi de aynı satırı görür, sonra biri diğerini kilitler. Bir şekilde kilitli satırı atlatmayı ve bekleyen bir sonraki öğeye gitmeyi umuyordum ..