2012-07-06 10 views
5

Estoy usando columnas rowversion para manejar la concurrencia optimista y quiero recuperar el nuevo valor rowversion cuando he hecho una actualización para que mi capa de datos tenga el último valor y puede realizar otra actualización obteniendo una excepción de concurrencia (a menos que otra persona haya actualizado el registro).Obteniendo el último valor rowversion/timestamp en la declaración de actualización - Servidor Sql

Estaba haciendo un get en la capa de datos después de hacer una actualización, pero esto no era muy eficiente o perfectamente confiable.

Para la siguiente tabla:

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

me trataron:

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 

pero no fue del todo feliz debido a la posibilidad de no obtener el valor rowverion de actualización de otra persona. Entonces me encontré con la instrucción de salida en la documentación rowversion (http://msdn.microsoft.com/en-us/library/ms182776.aspx/http://msdn.microsoft.com/en-us/library/ms177564.aspx) y intentado esto:

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 

Esto funciona bien. En mis pruebas básicas (solo ejecutando 10000 llamadas y cronometrando), la opción de SALIDA tarda aproximadamente un 40% más pero aún menos de medio milisegundo. Ninguno tomó un tiempo medible con SET STATISTICS TIME ON.

Mi pregunta es, ¿alguien sabe de una manera mejor/más simple de hacer esto?

Tenía la esperanza de una función que podría usar similar a SCOPE_IDENTITY() para las columnas de identidad, pero no puedo encontrar algo así. Alguien sabe si me estoy perdiendo algo?

Gracias de antemano.

+0

salida es el camino a seguir para recuperar cualquier valor generado en INSERT (y que incluye IDENTIDAD si me preguntas ...) –

+0

OK, gracias por eso. ¿Algún motivo en particular por el cual prefieres OUTPUT a SCOPE_IDENTITY? –

+2

Funciona con inserciones de varias filas –

Respuesta

0

De MSDN:

@@ DBTS devuelve el valor utilizado por última vez marca de tiempo de la base de datos actual. Se genera un nuevo valor de marca de tiempo cuando se inserta o actualiza una fila con una columna de marca de tiempo .

+2

Gracias, no sabía de eso. A menos que esté equivocado. no funcionaría de manera confiable en este escenario porque es una base de datos amplia (similar a @@ identity) en lugar de tener un alcance para el procedimiento (similar a SCOPE_IDENTITY()). –

+0

Tienes razón, eso es un inconveniente. Supongo que OUTPUT es el único camino que queda por recorrer. –

0

Su problema es que entre la actualización y seleccionar a alguien más actualiza las filas. Entonces, cuando selecciona después de su declaración de actualización, no obtiene los mismos valores. Este es un problema de lectura no repetible. Debería utilizar la sugerencia de bloqueo (UPDLOCK) con la declaración de actualización. Este bloqueo permitirá a los lectores (es decir, bloqueos compartidos) pero bloqueará a los escritores. Entonces obtendrás las mismas filas después de la actualización. Por lo tanto el procedimiento almacenado debe ser -

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 
Cuestiones relacionadas