Sangat banyak pemula di pekerjaan DB, jadi menghargai kesabaran Anda dengan pertanyaan dasar. Saya menjalankan SQL Server 2014 pada mesin lokal saya, dan saya punya meja kecil dan aplikasi klien dasar untuk menguji berbagai pendekatan dengan. Saya mendapatkan apa yang tampaknya menjadi kunci tabel selama keduanya INSERT INTO
dan UPDATE
pernyataan. Klien adalah aplikasi ASP.NET dengan kode berikut:
OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();
Saya menjalankan kode ini, lalu dari studio manajemen yang saya jalankan SELECT * FROM LAYOUTSv2
. Selama kedua kasus ketika utas klien dijeda (yaitu sebelum komit / rollback) kueri SELECT hang sampai komit / rollback terjadi.
Tabel memiliki bidang LAYOUTS_key yang ditetapkan sebagai kunci utama. Di jendela properti itu menunjukkan bahwa itu unik dan berkerumun, dengan kunci halaman dan kunci baris keduanya diizinkan. Pengaturan eskalasi kunci untuk tabel adalah Nonaktifkan ... Saya sudah mencoba kedua pengaturan lain yang tersedia dari Tabel dan AUTO tanpa perubahan. Saya sudah mencoba SELECT ... WITH (NOLOCK)
dan itu mengembalikan hasilnya segera, tetapi seperti yang diperingatkan dengan baik di sini dan di tempat lain, bukan itu yang seharusnya saya lakukan. Saya sudah mencoba memberi ROWLOCK
petunjuk pada kedua pernyataan INSERT
dan UPDATE
, tetapi tidak ada yang berubah.
Perilaku yang saya cari adalah ini: sebelum melakukan suatu INSERT
, kueri dari utas lain membaca semua baris kecuali yang sedang INSERT
diedit. Sebelum melakukan UPDATE
kueri dari utas lain, baca versi awal dari baris yang sedang UPDATE
diedit. Apakah ada cara saya bisa melakukan ini? Jika saya perlu memberikan informasi lain untuk mengklarifikasi kasus penggunaan saya, beri tahu saya. Terima kasih.
sumber
WHERE LAYOUTS_key='" + newkey + "'
adalah no-no lengkap untuk berbagai alasan termasuk injeksi SQL, Anda harus menggunakan query parameterised.newkey
ke "something';DELETE FROM LAYOUTSv2 --
". Pembaruan Anda akan selesai dengan sukses, dan kemudian mengosongkan tabel karena pengguna memanipulasi kueri dengan memasukkan tanda kutip. Biasanya, permintaan parameterisasi terlihat sepertiUDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?
, setelah itu Anda secara terpisah memberikan nilai ke?
(parameter) dalam kode Anda.Jawaban:
Kemungkinannya adalah tidak mengunci "seluruh tabel".
Mengunci baris dalam tabel tetapi Anda
SELECT * FROM LAYOUTSv2
mencoba membaca seluruh tabel sehingga harus diblokir oleh kunci itu.Untuk kasing, Anda dapat menentukan
READPAST
petunjuk untuk melewati baris yang terkunci - namun itu tidak akan memberikan hasil yang diinginkan untukUPDATE
kasing (kasing akan melewati baris lagi dan tidak membaca versi awal dari baris).Jika Anda mengonfigurasi database untuk isolasi snapshot yang sudah dibaca, ini akan memberikan efek yang Anda inginkan untuk kedua kasus (dengan mengorbankan penggunaan yang lebih besar dari
tempdb
)sumber
SNAPSHOT
isolasi untuk membiarkannya dinonaktifkan dan kemudian mengaktifkannya jika Anda kemudian memutuskan ini akan berguna untuk Anda.Pernyataan memasukkan dan memperbarui seharusnya membuat kunci tingkat baris. Namun, ketika jumlah kunci dalam transaksi apa pun adalah 5.000 atau lebih maka eskalasi kunci terjadi dan itu menciptakan kunci tingkat tabel. Silahkan lihat di bawah ini.
https://technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspx
sumber