[1] " , "
"":
CREATE TABLE dbo.CustomSequence (
FullTableName NVARCHAR(257) NOT NULL
CONSTRAINT PK_CustomSequence_FullTableName
PRIMARY KEY(FullTableName),
LastID INT NULL,
Start INT NOT NULL,
Seed INT NOT NULL
)
/ "" :
INSERT dbo.CustomSequence (FullTableName, LastID, Start, Seed)
VALUES
(N'dbo.Invoice', NULL, 1, 1),
(N'dbo.InvoiceDetail', NULL, 1, 1);
(!) Tx () UPDATE:
SET XACT_ABORT ON;
BEGIN TRAN;
...
DECLARE @InvNumOfIDs INT = 1, @InvFirstGeneratedIdentityValue INT;
UPDATE cs
SET @InvFirstGeneratedIdentityValue = LastID = IIF(cs.LastID IS NULL, cs.Start + (@InvNumOfIDs - 1) * cs.Seed, cs.LastID + @InvNumOfIDs * cs.Seed)
FROM dbo.CustomSequences cs
WHERE cs.FullTableName = N'dbo.Invoice';
...
INSERT dbo.Invoice (InvoiceID, CreateDate, ...)
VALUES (@InvFirstGeneratedIdentityValue, GETDATE(), ...)
...
COMMIT;
. ( - UPDATE - INSERT) Tx. , - INSERT - , Tx , ROLLBACK, - UPDATE, - .
№2: SET XACT_ABORT ON - Tx /.
№ 3: : , ? A: : READ UNCOMMITTED, READ COMMITTED ( SQL Server), REPETABLE READ, SERIALIZABLE.
# 4: Q: A: Tx (. ), (, dbo.Invoice), Tx [e]X[clusive] lock 'dbo.Invoice' dbo.CustomSequence, X loc k Tx → Tx, UPDATE ( dbo.Invoice table) Tx ( COMMIT ROLLBACK).
, Tx (s), (, dbo.Invoice), → INSERT (, dbo.Invoice ).
№ 5: Q: , Tx ( Tx) ? A: Tx (ROLLBACK) → UPDATE dbo.CustomSequence
(ROLLBACK) → Tx Tx.
# 6: Q: , Tx ( Tx) ? A: Tx COMMITED → , UPDATE dbo.CustomSequence, → Tx Tx.
# 7: Q: , (UPDATE dbo.CustomSequence INSERT dbo.Invoice) Tx (s)? INSERT , UPDATE dbo.CustomSequence → .
# 8: Q: , Tx → .
# 9: : Tx (s), dbo.Invoice dbo.InvoiceDetail, /.
[2] "" Gap-less (. )
allow concurrent INSERTs vs. block concurrent INSERTs (same target table)
sped vs. slow
gaps vs. no gaps (see
[3] , .