Ich habe, was auf den ersten Blick schien ein sehr einfaches Problem. Ich möchte in der Lage sein, einen eindeutigen Schlüsselwert mit einem Präfix zu erhalten. Ich habe eine Tabelle, die die Spalten 'Prefix' und 'Next_Value' enthält.Wie Transaktionsintegrität in SQL Server 2005 garantiert werden
Sie denken also, Sie starten einfach eine Transaktion, holen den nächsten Wert aus dieser Tabelle, inkrementieren den nächsten Wert in der Tabelle und commit, verketten das Präfix mit dem Wert, und Sie erhalten eine Reihe von eindeutigen alphanumerischen Schlüsseln .
Allerdings unter Last, mit verschiedenen Servern, die diese gespeicherte Proc über ADO.NET treffen, habe ich entdeckt, dass es von Zeit zu Zeit den gleichen Schlüssel an verschiedene Clients zurückgibt. Dies führt natürlich später zu einem Fehler, wenn der Schlüssel als Primärschlüssel verwendet wird!
Ich hatte naiv angenommen BEGIN TRAN ... COMMIT TRAN sicherte die Atomizität der Datenzugriffe innerhalb des Bereichs. Als ich das betrachtete, entdeckte ich Transaktionsisolationsebenen und fügte SERIALIZABLE als das restriktivste hinzu - ohne Freude.
Create proc [dbo].[sp_get_key]
@prefix nvarchar(3)
as
set tran isolation level SERIALIZABLE
declare @result nvarchar(32)
BEGIN TRY
begin tran
if (select count(*) from key_generation_table where prefix = @prefix) = 0 begin
insert into key_generation_table (prefix, next_value) values (@prefix,1)
end
declare @next_value int
select @next_value = next_value
from key_generation_table
where prefix = @prefix
update key_generation_table
set next_value = next_value + 1
where prefix = @prefix
declare @string_next_value nvarchar(32)
select @string_next_value = convert(nvarchar(32),@next_value)
commit tran
select @result = @prefix + substring('000000000000000000000000000000',1,10-len(@string_next_value)) + @string_next_value
select @result
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRAN
DECLARE @ErrorMessage NVARCHAR(400);
DECLARE @ErrorNumber INT;
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorLine INT;
SELECT @ErrorMessage = N'{' + convert(nvarchar(32),ERROR_NUMBER()) + N'} ' + N'%d, Line %d, Text: ' + ERROR_MESSAGE();
SELECT @ErrorNumber = ERROR_NUMBER();
SELECT @ErrorSeverity = ERROR_SEVERITY();
SELECT @ErrorState = ERROR_STATE();
SELECT @ErrorLine = ERROR_LINE();
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine)
END CATCH
Hier ist der Schlüssel Generation Tisch ...
CREATE TABLE [dbo].[Key_Generation_Table](
[prefix] [nvarchar](3) NOT NULL,
[next_value] [int] NULL,
CONSTRAINT [PK__Key_Generation_T__236943A5] PRIMARY KEY CLUSTERED
(
[prefix] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Welcher Teil des Schlüssels ist dupliziert? Vorwahl oder Nummer Teil? – gbn