Получение последнего значения rowversion/timestamp в операторе обновления - Sql Server

Я использую столбцы rowversion для обработки оптимистичного параллелизма и хочу вернуть новое значение rowversion, когда я выполню обновление, чтобы мой уровень данных имел самое последнее значение и мог выполнить другое обновление с получением исключения параллелизма (если запись не имеет был обновлен кем-то еще).

Я только что получил доступ к слою данных после обновления, но это было не очень эффективно и не совсем надежно.

Для следующей таблицы:

CREATE TABLE PurchaseType
(
    PurchaseTypeCode nvarchar(20) NOT NULL PRIMARY KEY CLUSTERED (PurchaseTypeCode),
    Name nvarchar(50) NOT NULL,
    TS rowversion NOT NULL
)

Я старался:

CREATE PROCEDURE PurchaseType_UpdateWithGet
@PurchaseTypeCode nvarchar(20),
@Name nvarchar(50),
@TS rowversion OUTPUT    
AS

UPDATE PurchaseType
SET Name = @Name
WHERE PurchaseTypeCode = @PurchaseTypeCode
 AND TS = @TS

SELECT @TS = TS FROM PurchaseType WHERE PurchaseTypeCode = @PurchaseTypeCode
GO

но не был полностью счастлив из-за возможности не получить значение rowverion от чужого обновления. Затем я наткнулся на инструкцию OUTPUT в документации по версии строк (http://msdn.microsoft.com/en-us/library/ms182776.aspx / http://msdn.microsoft.com/en-us/library/ms177564.aspx) и попробовал это:

CREATE PROCEDURE PurchaseType_UpdateWithOutput
@PurchaseTypeCode nvarchar(20),
@Name nvarchar(50),
@TS rowversion OUTPUT    
AS

DECLARE @Output TABLE (TS BINARY(8))

UPDATE PurchaseType
SET Name = @Name
    OUTPUT inserted.TS into @Output
WHERE PurchaseTypeCode = @PurchaseTypeCode
    AND TS = @TS

SELECT TOP 1 @TS = TS FROM @Output
GO

Это хорошо работает. В моих самых базовых тестах (просто выполнение 10000 вызовов и синхронизация) опция OUTPUT занимает примерно на 40% больше времени, но все еще меньше, чем полсекунды. Ни один из них не потребовал какого-либо измеримого времени при включенном параметре "Время для статистики"

Мой вопрос: кто-нибудь знает лучший / более простой способ сделать это?

Я надеялся на функцию, которую мог бы использовать аналогично SCOPE_IDENTITY() для столбцов идентификаторов, но не могу найти ничего подобного. Кто-нибудь знает, если я что-то упустил?

Заранее спасибо.

2 ответа

Из MSDN:

@@ DBTS возвращает значение последней использованной метки времени текущей базы данных. Новое значение временной метки генерируется, когда строка со столбцом временной метки вставляется или обновляется.

Ваша проблема в том, что между обновлением и выбором кто-то еще обновляет строки. Поэтому, когда вы выбираете после своего обновления, вы не получаете те же значения. Это проблема неповторяемого чтения. Вы должны использовать подсказку блокировки (UPDLOCK) с оператором обновления. Эта блокировка позволяет читателям (то есть разделяемым блокировкам), но блокирует писателей. Таким образом, вы получите те же строки после обновления. Таким образом, ваша хранимая процедура должна быть -

CREATE PROCEDURE PurchaseType_UpdateWithGet
@PurchaseTypeCode nvarchar(20),
@Name nvarchar(50),
@TS rowversion OUTPUT    
AS

UPDATE PurchaseType with (updlock)
SET Name = @Name
WHERE PurchaseTypeCode = @PurchaseTypeCode
 AND TS = @TS

SELECT @TS = TS FROM PurchaseType WHERE PurchaseTypeCode = @PurchaseTypeCode
GO
Другие вопросы по тегам