MySQL
PILIH ... UNTUK PEMBARUAN dengan PEMBARUAN
Menggunakan transaksi dengan InnoDB (komit otomatis dimatikan), SELECT ... FOR UPDATE
memungkinkan satu sesi untuk sementara mengunci catatan tertentu (atau catatan) sehingga tidak ada sesi lain yang dapat memperbaruinya. Kemudian, dalam transaksi yang sama, sesi tersebut benar-benar dapat melakukan UPDATE
pada catatan yang sama dan melakukan atau memutar kembali transaksi. Ini akan memungkinkan Anda untuk mengunci catatan sehingga tidak ada sesi lain yang dapat memperbaruinya sementara Anda mungkin melakukan logika bisnis lain.
Ini dilakukan dengan penguncian. InnoDB menggunakan indeks untuk mengunci catatan, jadi mengunci catatan yang ada tampaknya mudah--cukup mengunci indeks untuk catatan itu.
PILIH ... UNTUK PEMBARUAN dengan INSERT
Namun, untuk menggunakan SELECT ... FOR UPDATE
dengan INSERT
, bagaimana Anda mengunci indeks untuk catatan yang belum ada? Jika Anda menggunakan tingkat isolasi default REPEATABLE READ
, InnoDB juga akan memanfaatkan celah kunci. Asalkan Anda mengetahui id
(atau bahkan rentang id) untuk dikunci, maka InnoDB dapat mengunci celah tersebut sehingga tidak ada catatan lain yang dapat dimasukkan ke dalam celah itu sampai kita selesai melakukannya.
Jika id
. Anda kolom adalah kolom kenaikan otomatis, lalu SELECT ... FOR UPDATE
dengan INSERT INTO
akan bermasalah karena Anda tidak akan tahu apa id
yang baru adalah sampai Anda memasukkannya. Namun, karena Anda tahu id
yang ingin Anda masukkan, SELECT ... FOR UPDATE
dengan INSERT
akan berhasil.
PERINGATAN
Pada tingkat isolasi default, SELECT ... FOR UPDATE
pada catatan yang tidak ada tidak memblokir transaksi lainnya. Jadi, jika dua transaksi keduanya melakukan SELECT ... FOR UPDATE
pada catatan indeks yang tidak ada yang sama, keduanya akan mendapatkan kunci, dan tidak ada transaksi yang dapat memperbarui catatan. Bahkan, jika mereka mencoba, kebuntuan akan terdeteksi.
Oleh karena itu, jika Anda tidak ingin menghadapi kebuntuan, Anda dapat melakukan hal berikut:
MASUKKAN KE ...
Mulai transaksi, dan lakukan INSERT
. Lakukan logika bisnis Anda, dan lakukan atau batalkan transaksi. Segera setelah Anda melakukan INSERT
pada indeks catatan yang tidak ada pada transaksi pertama, semua transaksi lainnya akan diblokir jika mereka mencoba untuk INSERT
record dengan indeks unik yang sama. Jika transaksi kedua mencoba memasukkan catatan dengan indeks yang sama setelah transaksi pertama melakukan penyisipan, maka itu akan mendapatkan kesalahan "kunci duplikat". Tangani sebagaimana mestinya.
PILIH ... KUNCI DALAM MODE BERBAGI
Jika Anda memilih dengan LOCK IN SHARE MODE
sebelum INSERT
, jika transaksi sebelumnya telah memasukkan record tersebut tetapi belum melakukan commit, SELECT ... LOCK IN SHARE MODE
akan memblokir hingga transaksi sebelumnya selesai.
Jadi untuk mengurangi kemungkinan kesalahan kunci duplikat, terutama jika Anda menahan kunci beberapa saat saat menjalankan logika bisnis sebelum melakukan atau memutarnya kembali:
SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
- Jika tidak ada catatan yang dikembalikan, maka
INSERT INTO FooBar (foo, bar) VALUES (?, ?)