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 (?, ?)