5

Я пишу синхронизатор, который будет принимать все изменения в одной БД и синхронизировать их с другой БД. Для этого я добавил в моей таблице T две колонки:Есть ли возможное состояние гонки в этом заявлении UPDATE?

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

Теперь я могу легко выбрать все строки, которые были изменены с момента последней синхронизации:

select * from T where LastUpdate > LastSync 

Однако после выполнения синхронизации I Should сделайте два поля равными. Но обновление строки также обновляет метку времени, так что я должен сделать это:

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

Но мне интересно, - будет ли это всегда работает? Что, если я прочитаю значение @@DBTS, а затем другому пользователю удастся вставить/обновить строку где-нибудь до того, как моя строка будет зафиксирована? Является ли этот рискованный код? И если да - как это можно сделать лучше?

+0

Кстати, какая версия и выпуск SQL Server вы? [Изменить захват данных] (http://msdn.microsoft.com/en-us/library/bb522489.aspx) вариант? –

+0

@ Мартин Смит - 2008, я думаю. Не уверен, что у клиента. –

+0

@ Мартин Смит - я проверил захват данных изменений, но это было бы излишним. Простой временной метки будет достаточно. Мне нужно только знать, какие записи еще нужно синхронизировать. Мне не нужна полная история. –

ответ

-1

Если вы запустите это в транзакции Serializable, никакие другие чтения/записи не смогут повлиять на эти таблицы.

RepeateableRead может также сделать работу ...

+1

Столы - да. Но как насчет ценности '@@ DBTS'? Это не хранится ни в одной таблице! –

+0

@Vilx Если вы берете эксклюзивную блокировку таблицы на время синхронизации, то, по-видимому, не имеет значения, добавляет ли @ @ DBTS приращение событием в другой таблице. –

+0

@ Мартин Смит - но @@ DBTS является глобальным для всей БД. Почему это не имеет значения? Если я получу одно (более старое) значение для поля «LastSync» и новое для поля «LastUpdate», моя синхронизация будет нарушена. –

4

Сохранение «LastSync» в той же таблице, реальные данные, может быть, не очень хорошая идея. Попробуйте сохранить его в другой таблице, которая не имеет rowversion. Таким образом, вы избегаете того, чтобы «обновление строки также обновляло метку времени».

Ваше программное обеспечение синхронизатора может затем работать таким образом:

  • Получить значение @LastSync из дополнительной таблицы
  • "Выбрать @ThisSync = макс (LastUpdate) от T, где LastUpdate> @LastSync"
  • «Выберите * из T, где LastUpdate> @LastSync и LastUpdate < = @ThisSync" являются вашими строками для синхронизации
  • Храните @ThisSync в качестве новой «LastSync» в дополнительной таблице.

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

+0

Это идея. Я буду иметь в виду, на случай, если ничего лучше не появится. –

Смежные вопросы