Mengunci tabel mencegah pengguna DB lain mempengaruhi baris / tabel yang telah Anda kunci. Tapi kunci, di dalam dan dari dirinya sendiri, TIDAK akan memastikan bahwa logika Anda keluar dalam keadaan yang konsisten.
Pikirkan sistem perbankan. Saat Anda membayar tagihan secara online, setidaknya ada dua akun yang terpengaruh oleh transaksi tersebut: Akun Anda, tempat uang diambil. Dan akun penerima, tempat uang ditransfer. Dan rekening bank, tempat mereka akan dengan senang hati menyetorkan semua biaya layanan yang dibebankan pada transaksi tersebut. Mengingat (seperti yang diketahui semua orang akhir-akhir ini) bahwa bank sangat bodoh, katakanlah sistem mereka bekerja seperti ini:
$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;
$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance
Sekarang, tanpa kunci dan tanpa transaksi, sistem ini rentan terhadap berbagai kondisi balapan, yang terbesar adalah beberapa pembayaran yang dilakukan di akun Anda, atau akun penerima secara paralel. Sementara kode Anda telah mengambil saldo Anda dan melakukan huge_overdraft_fees () dan yang lainnya, sangat mungkin bahwa beberapa pembayaran lain akan menjalankan jenis kode yang sama secara paralel. Mereka akan mengambil saldo Anda (katakanlah, $ 100), melakukan transaksi mereka (ambil $ 20 yang Anda bayarkan, dan $ 30 yang mereka gunakan untuk mengacaukan Anda), dan sekarang kedua jalur kode memiliki dua saldo berbeda: $ 80 dan $ 70. Bergantung pada saldo mana yang terakhir kali berakhir, Anda akan mendapatkan salah satu dari dua saldo tersebut di akun Anda, bukan $ 50 yang seharusnya Anda dapatkan ($ 100 - $ 20 - $ 30). Dalam kasus ini, "kesalahan bank dalam keuntungan Anda"
Sekarang, katakanlah Anda menggunakan kunci. Pembayaran tagihan Anda ($ 20) menyentuh pipa terlebih dahulu, sehingga menang dan mengunci catatan akun Anda. Sekarang Anda memiliki penggunaan eksklusif, dan dapat mengurangi $ 20 dari saldo, dan menulis kembali saldo baru dengan damai ... dan akun Anda berakhir dengan $ 80 seperti yang diharapkan. Tapi ... uhoh ... Anda mencoba memperbarui akun penerima, dan akun itu terkunci, dan dikunci lebih lama dari yang diizinkan oleh kode, waktu transaksi Anda habis ... Kami berurusan dengan bank-bank bodoh, jadi alih-alih mengalami kesalahan yang tepat penanganan, kode hanya menarik exit()
, dan $ 20 Anda lenyap menjadi embusan elektron. Sekarang Anda kehabisan $ 20, dan Anda masih berhutang $ 20 ke receiver, dan telepon Anda diambil alih.
Jadi ... masukkan transaksi. Anda memulai transaksi, Anda mendebit akun Anda $ 20, Anda mencoba mengkredit penerima dengan $ 20 ... dan sesuatu meledak lagi. Tapi kali ini, alih-alih exit()
, kodenya bisa begitu saja rollback
, dan poof, $ 20 Anda secara ajaib ditambahkan kembali ke akun Anda.
Pada akhirnya, intinya adalah:
Kunci mencegah orang lain mengganggu catatan database apa pun yang Anda tangani. Transaksi mencegah kesalahan "nanti" mengganggu hal "sebelumnya" yang telah Anda lakukan. Tidak satu pun yang dapat menjamin bahwa semuanya berjalan dengan baik pada akhirnya. Tapi bersama-sama, mereka melakukannya.
dalam pelajaran besok: The Joy of Deadlocks.
Anda menginginkan
SELECT ... FOR UPDATE
atauSELECT ... LOCK IN SHARE MODE
di dalam transaksi, seperti yang Anda katakan, karena biasanya SELECT, tidak peduli apakah mereka dalam transaksi atau tidak, tidak akan mengunci tabel. Mana yang Anda pilih akan bergantung pada apakah Anda ingin transaksi lain dapat membaca baris itu saat transaksi Anda sedang berlangsung.http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
START TRANSACTION WITH CONSISTENT SNAPSHOT
tidak akan berhasil untuk Anda, karena transaksi lain masih bisa datang dan mengubah baris itu. Ini disebutkan tepat di bagian atas tautan di bawah.http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html
sumber
Konsep dan kunci transaksi berbeda. Namun, transaksi menggunakan kunci untuk membantunya mengikuti prinsip ACID. Jika Anda ingin tabel tersebut mencegah orang lain membaca / menulis pada titik waktu yang sama saat Anda membaca / menulis, Anda memerlukan kunci untuk melakukan ini. Jika Anda ingin memastikan integritas dan konsistensi data, sebaiknya gunakan transaksi. Saya pikir konsep campuran tingkat isolasi dalam transaksi dengan kunci. Silakan cari tingkat isolasi transaksi, SERIALIZE harus tingkat yang Anda inginkan.
sumber
Saya mengalami masalah yang sama saat mencoba
IF NOT EXISTS ...
dan kemudian melakukanINSERT
yang menyebabkan kondisi balapan saat beberapa utas memperbarui tabel yang sama.Saya menemukan solusi untuk masalah ini di sini: Bagaimana menulis pertanyaan INSERT IF NOT EXISTS dalam SQL standar
Saya menyadari ini tidak secara langsung menjawab pertanyaan Anda tetapi prinsip yang sama dalam melakukan pemeriksaan dan penyisipan sebagai satu pernyataan sangat berguna; Anda harus dapat memodifikasinya untuk melakukan pembaruan Anda.
sumber
Anda bingung dengan kunci & transaksi. Mereka adalah dua hal berbeda dalam RMDB. Kunci mencegah operasi bersamaan sementara transaksi berfokus pada isolasi data. Periksa ini artikel bagus untuk klarifikasi dan beberapa solusi anggun.
sumber
Saya akan menggunakan
untuk memulai, dan a
untuk mengakhiri.
Apa pun yang Anda lakukan di antaranya diisolasi dari pengguna lain database Anda jika mesin penyimpanan Anda mendukung transaksi (yaitu InnoDB).
sumber