Ich schreibe eine Prozedur, die Finical-Transaktionen in einer Live-Datenbank abgleicht. Die Arbeit, die ich mache, kann nicht als Set-Operation ausgeführt werden, daher verwende ich zwei verschachtelte Cursor.Korrekter Weg, eine exklusive Sperre zu übernehmen
Ich muss eine exklusive Sperre für die Transaktionstabelle nehmen, während ich pro Client abgleiche, aber ich möchte die Sperre freigeben und andere Personen ihre Abfragen zwischen jedem Client ausführen lassen, den ich verarbeite.
Ich würde gerne eine exklusive Sperre auf Zeilenebene anstelle einer Tischebene zu tun, aber what I have read so far sagt, dass ich nicht with (XLOCK, ROWLOCK, HOLDLOCK)
tun können, wenn die anderen Transaktionen auf READCOMMITED
Isolationsstufe ausgeführt wird (was es für mich ist).
Nehme ich eine Exclusionssperre auf Tabellenebene korrekt an, und gibt es in Server 2008 R2 eine Möglichkeit, Extensions auf Zeilenebene so einzurichten, wie ich möchte, ohne die anderen in der Datenbank ausgeführten Abfragen zu ändern?
declare client_cursor cursor local forward_only for
select distinct CLIENT_GUID from trnHistory
open client_cursor
declare @ClientGuid uniqueidentifier
declare @TransGuid uniqueidentifier
fetch next from client_cursor into @ClientGuid
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
begin tran
declare @temp int
--The following row will not work if the other connections are running READCOMMITED isolation level
--select @temp = 1
--from trnHistory with (XLOCK, ROWLOCK, HOLDLOCK)
--left join trnCB with (XLOCK, ROWLOCK, HOLDLOCK) on trnHistory.TRANS_GUID = trnCB.TRANS_GUID
--left join trnClients with (XLOCK, ROWLOCK, HOLDLOCK) on trnHistory.TRANS_GUID = trnClients.TRANS_GUID
--(Snip) --Other tables that will be "touched" during the reconcile
--where trnHistory.CLIENT_GUID = @ClientGuid
--Works allways but locks whole table.
select top 1 @temp = 1 from trnHistory with (XLOCK, TABLOCK)
select top 1 @temp = 1 from trnCB with (XLOCK, TABLOCK)
select top 1 @temp = 1 from trnClients with (XLOCK, TABLOCK)
--(Snip) --Other tables that will be "touched" during the reconcile
declare trans_cursor cursor local forward_only for
select TRANS_GUID from trnHistory where CLIENT_GUID = @ClientGuid order by TRANS_NUMBER
open trans_cursor
fetch next from trans_cursor into @TransGuid
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
--Do Work here
END
fetch next from trans_cursor into @TransGuid
END
close trans_cursor
deallocate trans_cursor
--commit the transaction and release the lock, this allows other
-- connections to get a few queries in while it is safe to read.
commit tran
END
fetch next from client_cursor into @ClientGuid
END
close client_cursor
deallocate client_cursor
Ich versuche herauszufinden, warum Sie eine exklusive Sperre benötigen. Werden wahrscheinlich andere Personen Datensätze einfügen? Andere Leute aktualisieren Datensätze? Sind Sie besorgt, dass andere Menschen die Daten nicht einheitlich sehen? – Laurence
@Laurence Ich mache mir Sorgen, dass andere Leute einen inkonsistenten Blickwinkel bekommen. Ich versuche, einen Fehler zu korrigieren, der einen kleinen Prozentsatz der Clients betrifft, aber dieser Korrekturprozess hinterlässt mehrere voneinander abhängige Zeilen in mehreren Tabellen (ich werde tatsächlich 5 Tabellen sperren, aber mein Codebeispiel auf eine Tabelle vereinfachen) in einem inkonsistenten Zustand Korrekturprozess. Die Inkonsistenz ist pro Client isoliert, aber wenn man einen 'SELECT SUM (ColA) FROM trnHistory' über diesen einen Client ausgibt, würde während des "Korrektur" -Prozesses ein falscher Wert zurückgegeben werden. Also muss ich eine exklusive Sperre nehmen, um Lesevorgänge zu verhindern. –
Ich verstehe nicht, warum eine Transaktion Sie nicht davor schützt, es sei denn, Sie haben Leute, die read_uncommitted tun. – Laurence