Bardzo początkujący w pracy z DB, więc doceń swoją cierpliwość w kwestii podstawowego pytania. Korzystam z programu SQL Server 2014 na moim komputerze lokalnym i mam małą tabelę oraz podstawową aplikację kliencką do testowania różnych metod. Dostaję coś, co wydaje się być blokadą tabeli podczas obu INSERT INTO
i UPDATE
instrukcji. Klient jest aplikacją ASP.NET z następującym kodem:
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();
Uruchamiam ten kod, a następnie uruchamiam ze studia zarządzania SELECT * FROM LAYOUTSv2
. W obu przypadkach, gdy wątek klienta jest wstrzymany (tj. Przed zatwierdzeniem / wycofaniem), zapytanie SELECT zawiesza się do momentu zatwierdzenia / wycofania.
Tabela ma pole LAYOUTS_key przypisane jako klucz podstawowy. W oknie właściwości pokazuje, że jest unikalny i klastrowany, z dozwolonymi blokadami stron i blokad wierszy. Ustawienie eskalacji blokady dla tabeli to Wyłącz ... Próbowałem obu pozostałych ustawień Tabeli i AUTO bez zmian. Próbowałem SELECT ... WITH (NOLOCK)
i to natychmiast zwraca wynik, ale jak to dobrze ostrzega tutaj i innych miejscach, nie jest to, co powinienem robić. Próbowałem ROWLOCK
wskazać zarówno na oświadczenia, jak INSERT
i na UPDATE
oświadczenia, ale nic się nie zmieniło.
Zachowanie, którego szukam, jest następujące: przed zatwierdzeniem INSERT
kwerendy z innych wątków czytają wszystkie wiersze z wyjątkiem tego, który jest INSERT
edytowany. Przed zatwierdzeniem UPDATE
zapytań z innych wątków przeczytaj początkową wersję edytowanego wiersza UPDATE
. Czy jest jakiś sposób, żeby to zrobić? Jeśli muszę podać inne informacje w celu wyjaśnienia mojego przypadku użycia, daj mi znać. Dzięki.
źródło
WHERE LAYOUTS_key='" + newkey + "'
jest to kompletne „nie” z różnych powodów, w tym wstrzykiwania SQL, należy stosować sparametryzowane zapytania.newkey
„something';DELETE FROM LAYOUTSv2 --
”. Aktualizacja zakończy się pomyślnie, a następnie opróżni tabelę, ponieważ użytkownik manipulował zapytaniem, wstawiając apostrof. Zwykle sparametryzowane zapytanie wygląda mniej więcej takUDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?
, po czym osobno przypisujesz wartości do?
parametru w swoim kodzie.Odpowiedzi:
Możliwe, że nie blokuje „całego stołu”.
Blokuje wiersz w tabeli, ale
SELECT * FROM LAYOUTSv2
próbujesz odczytać cały stół, więc koniecznie jest blokowany przez tę blokadę.W przypadku wstawiania możesz jedynie wskazać
READPAST
wskazówkę, aby pominąć zablokowanyUPDATE
wiersz - nie da to jednak pożądanego rezultatu w przypadku (ponownie pominie wiersz, nie czytając początkowej wersji wiersza).Jeśli skonfigurujesz bazę danych do odczytu zatwierdzonej izolacji migawki , da to pożądany efekt w obu przypadkach (kosztem większego wykorzystania
tempdb
)źródło
SNAPSHOT
izolacji, najlepiej pozostaw ją wyłączoną, a następnie włącz ją, jeśli później zdecydujesz, że będzie to dla Ciebie przydatne.Instrukcje wstawiania i aktualizacji powinny tworzyć blokady na poziomie wiersza. Jednak gdy liczba blokad w dowolnej transakcji wynosi 5000 lub więcej, następuje eskalacja blokady i tworzy ona blokadę na poziomie tabeli. Patrz poniżej.
https://technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspx
źródło