Alih-alih FOR UPDATE
gunakan LOCK IN SHARE MODE
. FOR UPDATE
mencegah transaksi lain untuk membaca baris juga. LOCK IN SHARE MODE
memungkinkan membaca, tetapi mencegah pembaruan.
Referensi:Manual MySQL
------ sesi 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- sesi 2 (yang tidak diblokir lagi :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Pembaruan:
Menyadari bahwa tabel tidak memiliki indeks pada t
, saya punya penjelasannya sebagai berikut:
Pertama, transaksi T1 mengunci baris 1 di SELECT * FROM test WHERE t=1 FOR UPDATE
Selanjutnya, transaksi T2 mencoba mengeksekusi UPDATE test SET NAME='irfandd' WHERE t=4
. Untuk mengetahui baris mana yang terpengaruh, perlu memindai semua baris, termasuk baris 1 . Tapi itu terkunci, jadi T2 harus menunggu sampai T1 selesai. Jika ada jenis indeks, WHERE t=4
dapat menggunakan indeks untuk memutuskan apakah baris 1 berisi t=4
atau tidak, jadi tidak perlu menunggu.
Opsi 1: tambahkan indeks pada test.t
sehingga pembaruan Anda dapat menggunakannya.
Opsi 2: gunakan LOCK IN SHARE MODE
, yang dimaksudkan untuk menempatkan kunci baca saja. Sayangnya opsi ini membuat kebuntuan. Menariknya, transaksi T2 dijalankan (memperbarui baris 4), dan T1 gagal (memperbarui baris 2). Tampaknya T1 read-lock baris 4 juga, dan karena T2 memodifikasinya, T1 gagal karena tingkat isolasi transaksi (BACA BERULANG secara default
). Solusi terakhir adalah bermain dengan Tingkat Isolasi Transaksi , menggunakan READ UNCOMMITTED
atau READ COMMITTED
tingkat transaksi.
Yang paling sederhana adalah Opsi 1 , IMHO, tapi terserah Anda.