5

Estoy escribiendo un software sincronizador que tomará todos los cambios en una base de datos y los sincronizará con otra base de datos. Con este fin he añadido en mi mesa T dos columnas:¿Existe una posible condición de carrera en esta declaración de ACTUALIZACIÓN?

alter table T add LastUpdate rowversion, LastSync binary(8) not null default 0 

Ahora puedo seleccionar fácilmente todas las filas que han cambiado desde la última sincronización:

select * from T where LastUpdate > LastSync 

Sin embargo después de realizar la sincronización de lo que debería hacer que los dos campos sean iguales. Sin embargo, la actualización de la fila también actualiza la marca de tiempo, por lo que tiene que hacer esto:

update T set [email protected]@DBTS+1 where [email protected] 

Pero me pregunto - se presente siempre funciona? ¿Qué pasa si leo el valor de @@DBTS y luego otro usuario logra insertar/actualizar una fila en alguna parte antes de que se comprometa mi fila? ¿Es este código arriesgado? Y si es así, ¿cómo podría mejorarse?

+0

Por cierto, ¿en qué versión y edición de SQL Server se encuentra? ¿Es [Change Data Capture] (http://msdn.microsoft.com/en-us/library/bb522489.aspx) una opción? –

+0

@Martin Smith - 2008, creo. No estoy seguro de lo que tiene el cliente –

+0

@Martin Smith - Revisé la captura de datos modificados, pero sería una exageración. Una simple marca de tiempo será suficiente. Solo necesito saber qué registros aún deben sincronizarse. No necesito el historial completo. –

Respuesta

-1

Si ejecuta esto en una transacción Serializable, entonces ninguna otra lectura/escritura podrá afectar estas tablas.

RepeateableRead también puede hacer el trabajo ...

+1

Tablas - sí. Pero, ¿qué pasa con el valor de '@@ DBTS'? ¡Eso no está almacenado en ninguna tabla! –

+0

@Vilx Si toma un bloqueo exclusivo de tabla durante la sincronización, entonces presumiblemente no importa si '@@ DBTS' se incrementa por un evento en otra tabla. –

+0

@Martin Smith - pero @@ DBTS es global para toda la base de datos. ¿Por qué no importa? Si obtengo un valor (más antiguo) para el campo 'LastSync', y uno más reciente para el campo' LastUpdate', mi sincronización se romperá. –

4

Almacenamiento "LastSync" en la misma mesa que los datos reales no es tal vez una buena idea en absoluto. Intente almacenarlo en otra tabla que no tenga una versión de fila. De esta forma evitará la "actualización de la fila también actualiza el problema de la marca de tiempo".

El software sincronizador continuación, puede trabajar de esta manera:

  • Obtener el valor @LastSync de la tabla adicional
  • "Seleccionar @ThisSync = max (LastUpdate) de T, donde LastUpdate> @LastSync"
  • "Seleccione * de T donde LastUpdate> @ LastSync y LastUpdate < = @ThisSync" son sus filas para sincronizar
  • Almacene @ThisSync como el nuevo "LastSync" en la tabla adicional.

Las entradas que se modifican mientras se ejecuta la sincronización tendrán un valor de versión de fila mayor que la consulta max(). Se sincronizarán la próxima vez que se llame a su sincronizador.

+0

Esa es una idea. Lo tendré en cuenta, en caso de que no surja nada mejor. –

Cuestiones relacionadas