Katakanlah Anda memiliki kode berikut (abaikan saja itu buruk):
BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else
Bagi saya, ini BUKAN mengelola konkurensi dengan benar. Hanya karena Anda melakukan transaksi tidak berarti orang lain tidak akan membaca nilai yang sama dengan yang Anda lakukan sebelum Anda mendapatkan pernyataan pembaruan Anda.
Sekarang, biarkan kode apa adanya (saya menyadari ini lebih baik ditangani sebagai satu pernyataan atau bahkan lebih baik menggunakan kolom autoincrement / identitas) apa cara yang pasti untuk membuatnya menangani konkurensi dengan benar dan mencegah kondisi balapan yang memungkinkan dua klien untuk mendapatkan yang sama nilai id?
Saya cukup yakin bahwa menambahkan WITH (UPDLOCK, HOLDLOCK)
ke SELECT akan melakukan trik. The tingkat isolasi transaksi Serializable akan tampaknya bekerja juga karena itu menyangkal orang lain untuk membaca apa yang Anda lakukan sampai tran berakhir ( UPDATE :. Ini salah See Martin jawaban). Benarkah? Apakah keduanya akan bekerja dengan baik? Apakah yang satu lebih disukai daripada yang lain?
Bayangkan melakukan sesuatu yang lebih sah daripada pembaruan ID - beberapa perhitungan berdasarkan pembacaan yang perlu Anda perbarui. Mungkin ada banyak tabel yang terlibat, beberapa di antaranya akan Anda tulis dan yang lain tidak. Apa praktik terbaik di sini?
Setelah menulis pertanyaan ini, saya pikir petunjuk kunci lebih baik karena Anda hanya mengunci tabel yang Anda butuhkan, tapi saya menghargai masukan siapa pun.
PS Dan tidak, saya tidak tahu jawaban terbaik dan benar-benar ingin mendapatkan pemahaman yang lebih baik! :)
update
yang mungkin didasarkan pada data yang sudah usang? Jika yang terakhir, Anda dapat menggunakanrowversion
kolom untuk memeriksa apakah baris yang akan diperbarui belum diubah sejak dibaca.Jawaban:
Hanya menangani
SERIALIZABLE
aspek level isolasi. Ya ini akan berhasil tetapi dengan risiko jalan buntu.Dua transaksi akan dapat membaca baris secara bersamaan. Mereka tidak akan memblokir satu sama lain karena mereka akan mengambil
S
kunci objek atauRangeS-S
kunci indeks tergantung pada struktur tabel dan kunci ini kompatibel . Tetapi mereka akan memblokir satu sama lain ketika mencoba untuk mendapatkan kunci yang diperlukan untuk pembaruan (IX
kunci objek atau indeksRangeS-U
masing-masing) yang akan menyebabkan kebuntuan.Penggunaan
UPDLOCK
petunjuk eksplisit sebagai gantinya akan membuat serial bacaan sehingga menghindari risiko kebuntuan.sumber
IX
menjadiX
di tumpukan itu sendiri. Menariknya tidak ada baris yang memenuhi syarat sehingga tidak ada kunci baris yang dapat dikeluarkan. Tidak yakin mengapa dibutuhkanX
kunci sama sekali.Saya pikir pendekatan terbaik bagi Anda adalah dengan benar-benar mengekspos modul Anda ke konkurensi tinggi dan lihat sendiri. Terkadang UPDLOCK saja sudah cukup, dan tidak perlu untuk HOLDLOCK. Terkadang sp_getapplock bekerja dengan sangat baik. Saya tidak akan membuat pernyataan selimut di sini - kadang menambahkan satu indeks lagi, pemicu, atau tampilan indeks mengubah hasilnya. Kita perlu menekankan kode uji dan melihat sendiri berdasarkan kasus per kasus.
Saya telah menulis beberapa contoh pengujian stres di sini
Sunting: untuk pengetahuan internal yang lebih baik, Anda dapat membaca buku-buku Kalen Delaney. Namun, buku mungkin tidak sinkron seperti dokumentasi lainnya. Selain itu, ada terlalu banyak kombinasi untuk dipertimbangkan: enam tingkat isolasi, banyak jenis kunci, indeks berkerumun / nonclustered dan siapa yang tahu apa lagi. Itu banyak kombinasi. Selain itu, SQL Server adalah sumber tertutup, jadi kami tidak dapat mengunduh kode sumber, men-debug-nya dan semacamnya - yang akan menjadi sumber utama pengetahuan. Hal lain mungkin tidak lengkap atau ketinggalan jaman setelah rilis berikutnya atau paket layanan.
Jadi, Anda tidak boleh memutuskan apa yang berfungsi untuk sistem Anda tanpa pengujian stres Anda sendiri. Apa pun yang Anda baca, ini dapat membantu Anda memahami apa yang sedang terjadi, tetapi Anda harus membuktikan bahwa saran yang Anda baca bermanfaat untuk Anda. Saya tidak berpikir ada yang bisa melakukannya untuk Anda.
sumber
Dalam kasus khusus ini, penambahan
UPDLOCK
kunci pada kunciSELECT
memang akan mencegah anomali. PenambahanHOLDLOCK
tidak diperlukan karena kunci pembaruan diadakan selama durasi transaksi, tetapi saya akui untuk memasukkannya sendiri sebagai kebiasaan (mungkin buruk) di masa lalu.Tidak ada praktik terbaik. Pilihan Anda untuk kontrol konkurensi harus didasarkan pada persyaratan aplikasi. Beberapa aplikasi / transaksi perlu dieksekusi seolah-olah mereka memiliki kepemilikan eksklusif atas basis data, menghindari anomali dan ketidakakuratan di semua biaya. Aplikasi / transaksi lain dapat mentolerir beberapa tingkat gangguan dari satu sama lain.
Edit: @ komentar AlexKuznetsov mendorong saya membaca kembali pertanyaan dan menghapus kesalahan yang sangat jelas dalam jawaban saya. Catatan untuk diri sendiri pada posting larut malam.
sumber