Работа с отслеживанием изменений (SQL Server)

Применяется к:SQL ServerAzure SQL DatabaseAzure, управляемому экземпляру SQL Azure

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

Получение изменений с помощью функций отслеживания изменений

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

Сведения о функциях отслеживания изменений

Чтобы получить изменения из базы данных и сведения об этих изменениях, приложения могут использовать следующие функции.

Функция CHANGETABLE(CHANGES ...)
Эта функция, возвращающая набор строк, используется в запросе данных отслеживания изменений. Функция запрашивает данные, хранящиеся во внутренних таблицах отслеживания изменений. Она возвращает результирующий набор, содержащий первичные ключи измененных строк, а также другие сведения: операцию, число обновленных столбцов и версии строк.

Функция CHANGETABLE(CHANGES ...) получает в качестве аргумента последнюю версию синхронизации. Версию последней синхронизации можно получить с помощью переменной @last_synchronization_version. Семантика последней версии синхронизации выглядит следующим образом.

  • Вызывающий клиент получает сведения обо всех изменениях, происшедших до момента последней синхронизированной версии включительно.

  • Функция CHANGETABLE(CHANGES ...) поэтому возвращает сведения обо всех изменениях, произошедших после последней версии синхронизации.

    Ниже показано, как функция CHANGETABLE(CHANGES ...) используется для получения изменений.

    Diagram that shows an example of change tracking query output.

    В этом примере клиент A последний синхронизирован в 9:30, а клиент B последний синхронизирован в 10:30. В 10:00 и снова в 11:00 были внесены некоторые изменения в данные. Эти отслеживаемые изменения приведены ниже.

    CHANGETABLE(CHANGE...) Выходные данные — 11:30

    Клиент A последний синхронизирован в 9:30 утра.

    Код продукта Операция Столбцы
    139 Изменить Имя, цена
    140 Удаление -
    141 Insert -

    Клиент B последний синхронизирован в 10:30.

    Код продукта Операция Столбцы
    139 Изменить Цена
    140 Удаление -
    141 Изменить Цена

Функция CHANGE_TRACKING_CURRENT_VERSION()
Используется для получения текущей версии, которая будет использоваться при следующем запросе изменений. Эта версия представляет версию последней зафиксированной транзакции.

Функция CHANGE_TRACKING_MIN_VALID_VERSION()
Используется для получения минимальной допустимой версии, которую может иметь клиент и по-прежнему получать допустимые результаты из CHANGETABLE(). Клиент должен сравнить последнюю версию синхронизации со значением, возвращенным этой функцией. Если номер последней версии синхронизации меньше, чем возвращает эта функция, то он не сможет получить достоверные результаты из функции CHANGETABLE() и должен повторно инициализировать данные.

Получение исходных данных

Прежде чем приложение в первый раз получит изменения, оно должно выполнить запрос для получения первоначальных данных и версии синхронизации. Приложение должно получить соответствующие данные напрямую из таблицы, а затем вызвать функцию CHANGE_TRACKING_CURRENT_VERSION() для получения первоначальной версии. Эта версия передается функции CHANGETABLE(CHANGES ...) при первом получении изменений.

В следующем примере показано получение первоначальной версии синхронизации и первоначального набора данных.

declare @synchronization_version bigint;

-- Obtain the current synchronization version. This will be used next time that changes are obtained.
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();

-- Obtain initial data set.
SELECT
    P.ProductID, P.Name, P.ListPrice
FROM
   SalesLT.Product AS P;

Использование функций отслеживания изменений для получения изменений

Чтобы получить измененные строки для таблицы и сведения об изменениях, используйте CHANGETABLE(CHANGES...). Например, следующий запрос получает изменения для SalesLT.Product таблицы.

declare @last_synchronization_version bigint;

SELECT
    CT.ProductID, CT.SYS_CHANGE_OPERATION,
    CT.SYS_CHANGE_COLUMNS, CT.SYS_CHANGE_CONTEXT
FROM
    CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT;

Как правило, клиенту нужно получить последние данные строки, а не просто первичные ключи. Поэтому приложение соединяет результаты запроса функции CHANGETABLE(CHANGES ...) с данными в пользовательской таблице. Например, следующий запрос соединяется с таблицей SalesLT.Product , чтобы получить значения столбцов Name и ListPrice . Обратите внимание на использование OUTER JOIN. Это требуется, чтобы убедиться, что возвращаются сведения об изменениях в строках, удаленных из пользовательской таблицы.

SELECT
    CT.ProductID, P.Name, P.ListPrice,
    CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
    CT.SYS_CHANGE_CONTEXT
FROM
    SalesLT.Product AS P
RIGHT OUTER JOIN
    CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT
ON
    P.ProductID = CT.ProductID;

Чтобы получить версию, которая будет использоваться в следующем перечислении изменений, используется функция CHANGE_TRACKING_CURRENT_VERSION(), как показано в следующем примере.

SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();

Когда приложение получает изменения, оно должно использовать как функцию CHANGETABLE(CHANGES...), так и CHANGE_TRACKING_CURRENT_VERSION(), как показано в следующем примере.

-- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called.
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();

-- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized.
SELECT
    CT.ProductID, P.Name, P.ListPrice,
    CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
    CT.SYS_CHANGE_CONTEXT
FROM
    SalesLT.Product AS P
RIGHT OUTER JOIN
    CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT
ON
    P.ProductID = CT.ProductID;

Номера версий

База данных, для которой включено отслеживание изменений, содержит счетчик версий, который увеличивается при каждом изменении отслеживаемых таблиц. Каждой изменяемой строке присваивается собственный номер версии. Когда в приложение отправляется запрос изменений, вызывается функция, возвращающая номер версии. Эта функция возвращает сведения обо всех изменениях, которые были сделаны после этой версии. В некотором роде версия отслеживания изменений напоминает тип данных rowversion .

Проверка последней синхронизированной версии

Сведения об изменениях хранятся ограниченное время. Длительность этого времени управляется параметром CHANGE_RETENTION, который указывается в инструкции ALTER DATABASE.

Время, указанное для CHANGE_RETENTION, определяет, насколько часто все приложения должны запрашивать изменения из базы данных. Если приложение имеет значение для last_synchronization_version , которое старше минимальной допустимой версии синхронизации для таблицы, это приложение не может выполнить допустимое перечисление изменений. Это объясняется тем, что некоторые данные изменений могли быть очищены. Прежде чем приложение получает изменения с помощью CHANGETABLE(CHANGES ...), приложение должно проверить значение last_synchronization_version, что оно планирует передать в CHANGETABLE(CHANGES ...). Если значение last_synchronization_version недопустимо, это приложение должно повторно инициализировать все данные.

В следующем примере показано, как проверять достоверность значения last_synchronization_version для каждой таблицы.

-- Check individual table.
IF (@last_synchronization_version < CHANGE_TRACKING_MIN_VALID_VERSION(
                                   OBJECT_ID('SalesLT.Product')))
BEGIN
  -- Handle invalid version and do not enumerate changes.
  -- Client must be reinitialized.
END;

Как показано в следующем примере, достоверность значения last_synchronization_version можно проверить для всех таблиц в базе данных.

-- Check all tables with change tracking enabled
IF EXISTS (
  SELECT 1 FROM sys.change_tracking_tables
  WHERE min_valid_version > @last_synchronization_version )
BEGIN
  -- Handle invalid version & do not enumerate changes
  -- Client must be reinitialized
END;

Использование отслеживания столбцов

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

Сведения об отслеживании столбцов отображаются в столбце SYS_CHANGE_COLUMNS, который возвращается функцией CHANGETABLE(CHANGES ...).

Отслеживание столбцов можно использовать, чтобы значение NULL возвращалось для столбца, который не изменился. Если значение NULL недопустимо для того или иного столбца, можно возвратить отдельный столбец, который укажет, изменялись ли данные этого столбца.

В следующем примере столбец будет иметь NULL значение, CT_ThumbnailPhoto если этот столбец не изменился. Этот столбец может также принимать значение NULL , потому что он был изменен на NULL , поэтому приложение может использовать столбец CT_ThumbNailPhoto_Changed , чтобы определить, происходили ли изменения.

DECLARE @PhotoColumnId int = COLUMNPROPERTY(
    OBJECT_ID('SalesLT.Product'),'ThumbNailPhoto', 'ColumnId');

SELECT
    CT.ProductID, P.Name, P.ListPrice, -- Always obtain values.
    CASE
           WHEN CHANGE_TRACKING_IS_COLUMN_IN_MASK(
                     @PhotoColumnId, CT.SYS_CHANGE_COLUMNS) = 1
            THEN ThumbNailPhoto
            ELSE NULL
      END AS CT_ThumbNailPhoto,
      CHANGE_TRACKING_IS_COLUMN_IN_MASK(
                     @PhotoColumnId, CT.SYS_CHANGE_COLUMNS) AS
                                   CT_ThumbNailPhoto_Changed,
     CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
     CT.SYS_CHANGE_CONTEXT
FROM
     SalesLT.Product AS P
INNER JOIN
     CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT
ON
     P.ProductID = CT.ProductID AND
     CT.SYS_CHANGE_OPERATION = 'U';

Получение согласованных и правильных результатов

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

Например, чтобы получить изменения, внесенные в таблицу Sales и SalesOrders таблицу, приложение выполнит следующие действия:

  1. Проверить последнюю синхронизированную версию с помощью функции CHANGE_TRACKING_MIN_VALID_VERSION().

  2. Получить версию, которая будет использована для получения изменений в следующий раз, с помощью функции CHANGE_TRACKING_CURRENT_VERSION().

  3. Получите изменения для Sales таблицы с помощью CHANGETABLE(CHANGES ...).

  4. Получите изменения для SalesOrders таблицы с помощью CHANGETABLE(CHANGES ...).

В базе данных выполняются следующие два процесса, которые могут повлиять на результаты, возвращаемые на предыдущих шагах.

  • Процесс очистки выполняется в фоновом режиме и удаляет данные отслеживания изменений старше указанного срока хранения.

    Процесс очистки является отдельным фоновым процессом и руководствуется сроком хранения, заданным при настройке отслеживания изменений в базе данных. Проблема заключается в том, что он может выполняться в промежуток между проверкой последней версии синхронизации и вызовом функции CHANGETABLE(CHANGES...). Последняя версия синхронизации, которая была действительна, может быть недействительна к моменту получения изменений. Поэтому функция может возвратить неверные результаты.

  • Текущие операции DML выполняются в продажах и SalesOrders таблицах, таких как следующие операции:

    • В таблицах могут происходить изменения после того, как с помощью функции CHANGE_TRACKING_CURRENT_VERSION() была получена последняя версия синхронизации. Следовательно, функция может вернуть больше изменений, чем ожидалось.

    • Транзакция может зафиксировать время между вызовом получения изменений из Sales таблицы и вызовом получения изменений из SalesOrders таблицы. Таким образом, результаты таблицы SalesOrder могут иметь значение внешнего ключа, которое не существует в Sales таблице.

Для преодоления приведенных выше проблем рекомендуется применять изоляцию моментального снимка. Это позволит обеспечить согласованность сведений об изменениях и избежать соперничества при выполнении задач фоновой очистки. Если вы не используете транзакции моментальных снимков, разработка приложения, использующего отслеживание изменений, может потребовать значительно больше усилий.

Использование изоляции моментальных снимков

Отслеживание изменений было разработано для слаженной работы вместе с изоляцией моментального снимка. В базе данных необходимо активировать изоляцию моментального снимка. Все шаги, необходимые для получения изменений, должны включаться в транзакцию моментального снимка. Это гарантирует, что все изменения, внесенные в данные при получении изменений, не будут видны запросам внутри транзакции моментального снимка.

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

  1. Установите уровень изоляции транзакции на уровень моментальных снимков и запустите транзакцию.

  2. Проверьте последнюю версию синхронизации с помощью функции CHANGE_TRACKING_MIN_VALID_VERSION().

  3. Получите версию, которая будет использоваться в следующий раз, с помощью функции CHANGE_TRACKING_CURRENT_VERSION().

  4. Получение изменений для Sales таблицы с помощью CHANGETABLE(CHANGES ...)

  5. Получение изменений для SalesOrders таблицы с помощью CHANGETABLE(CHANGES ...)

  6. Зафиксируйте транзакцию.

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

  • Если очистка происходит после последней версии синхронизации, результаты из CHANGETABLE(CHANGES ...) по-прежнему будут допустимы, так как операции удаления, выполняемые очисткой, не будут отображаться внутри транзакции.

  • Любые изменения, внесенные в Sales таблицу или SalesOrders таблицу после получения следующей версии синхронизации, не будут видны, и вызовы CHANGETABLE(CHANGES ...) никогда не будут возвращать изменения с версией позже, чем возвращенная CHANGE_TRACKING_CURRENT_VERSION(). Согласованность между Sales таблицей и SalesOrders таблицей также будет поддерживаться, так как транзакции, зафиксированные во время между вызовами CHANGETABLE(CHANGES ...), не будут видны.

В следующем примере показано включение изоляции моментального снимка в базе данных.

-- The database must be configured to enable snapshot isolation.
ALTER DATABASE AdventureWorksLT
    SET ALLOW_SNAPSHOT_ISOLATION ON;

Транзакция моментального снимка используется следующим образом.

SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN
  -- Verify that version of the previous synchronization is valid.
  -- Obtain the version to use next time.
  -- Obtain changes.
COMMIT TRAN

Дополнительные сведения о транзакциях моментальных снимков см. в разделе SET TRANSACTION ISOLATION LEVEL (Transact-SQL).

Очистка и изоляция моментальных снимков

Включение изоляции моментальных снимков и отслеживания изменений в одной базе данных или в двух разных базах данных в одном экземпляре может привести к удалению строк sys.syscommittab с истекшим сроком действия при наличии открытой транзакции в базе данных с изоляцией моментального снимка. Это может произойти, поскольку процесс очистки с отслеживанием изменений учитывает нижнюю конечную точку в масштабе всего экземпляра (которая является безопасной версией очистки) при выполнении очистки. Это делается, чтобы процесс автоматической очистки отслеживания изменений не удалял строки, которые могут потребоваться открытой транзакцией в базе данных с включенной изоляцией моментальных снимков. Сохраняйте фиксацию моментальных снимков чтения и транзакции изоляции моментальных снимков как можно короче, чтобы обеспечить своевременное очистку просроченных строк sys.syscommittab .

Альтернативные варианты изоляции моментальных снимков

Существуют альтернативы использованию изоляции моментального снимка, но они требуют больше усилий, чтобы обеспечить требования всех приложений. Чтобы убедиться, что last_synchronization_version является допустимым и данные не удаляются процессом очистки перед получением изменений, выполните следующие действия.

  1. Проверьте параметр last_synchronization_version после вызовов функции CHANGETABLE().

  2. Проверяйте параметр last_synchronization_version в составе каждого запроса, чтобы получить изменения с помощью функции CHANGETABLE().

Изменения могут происходить после получения версии синхронизации для следующего перечисления. Для обхода этой ситуации существует два способа. Используемый вариант зависит от приложения и обработки побочных эффектов каждого подхода.

  • Пропускайте изменения с версиями больше, чем новая версия синхронизации.

    Побочный эффект этого подхода заключается в том, что новая или обновленная строка будет пропущена, если она была создана или обновлена перед версией новой синхронизации, а затем обновлена после нее. Если есть новая строка, проблема целостности ссылок может возникнуть, если в другой таблице существовала строка, которая ссылалась на пропущенную строку. Если есть обновленная строка, строка будет пропущена и не синхронизирована до следующего раза.

  • Включайте все изменения, даже с версиями больше, чем версия новой синхронизации.

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

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

Заметка

Выбор оптимального подхода для приложения, работающего с отслеживанием изменений, или любого пользовательского средства отслеживания изменений требует тщательного анализа. Поэтому намного проще использовать изоляцию моментального снимка.

Как отслеживание изменений обрабатывает изменения в базе данных

Некоторые приложения, использующие отслеживание изменений, выполняют двустороннюю синхронизацию с другими хранилищами данных. То есть изменения, внесенные в базу данных SQL Server, обновляются в другом хранилище данных, а изменения, внесенные в другое хранилище, обновляются в базе данных SQL Server.

Если приложение обновляет локальную базу данных изменениями, сделанными в другом хранилище данных, оно должно выполнить следующие операции.

  • Проверить наличие конфликтов.

    Конфликт возникает, когда одни и те же данные одновременно изменяются в обоих хранилищах данных. Приложение должно иметь возможность проверить наличие конфликта и получить достаточно информации для его разрешения.

  • Сохранить контекстные сведения приложения.

    Приложение хранит данные, с которыми связана информация отслеживания изменений. Эта информация должна быть доступна вместе с другими данными отслеживания изменений, если изменения были получены из локальной базы данных. Типичный пример таких контекстных сведений – идентификатор хранилища данных, которое было источником изменений.

Для выполнения вышеуказанных операций приложение синхронизации может использовать следующие функции:

  • CHANGETABLE(VERSION...)

    Когда приложение выполняет изменения, оно может использовать эту функцию для проверки конфликтов. Функция получает последние данные отслеживания изменений в заданной строке в таблицу отслеживания изменений. Эти данные содержат версию последней измененной строки. Это позволяет приложению определить, изменилась ли строка с момента последней синхронизации приложения.

  • WITH CHANGE_TRACKING_CONTEXT

    Приложение может использовать это предложение для хранения контекстных данных.

Проверка наличия конфликтов

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

В следующем примере показано использование функции CHANGETABLE(VERSION ...) для проверки конфликтов самым эффективным способом — без отдельного запроса. В примере CHANGETABLE(VERSION ...) определяет SYS_CHANGE_VERSION для строки, заданной аргументом @product id. CHANGETABLE(CHANGES ...) может получить те же сведения, но это будет менее эффективным. Если значение SYS_CHANGE_VERSION строки больше значения @last_sync_version, возникает конфликт. Если возникает конфликт, строка не будет обновлена. Проверка ISNULL() необходима, поскольку для строки может не иметься информации об изменениях. Если строка не была обновлена, так как отслеживание изменений было включено или после очистки информации об изменении не было.

-- Assumption: @last_sync_version has been validated.
UPDATE SalesLT.Product
SET ListPrice = @new_listprice
FROM SalesLT.Product AS P
WHERE ProductID = @product_id
    AND @last_sync_version >= ISNULL((
            SELECT CT.SYS_CHANGE_VERSION
            FROM CHANGETABLE(VERSION SalesLT.Product, (ProductID), (P.ProductID)) AS CT
            ), 0);

Следующий код проверяет обновленное число строк и может предоставить более подробные сведения о конфликте.

-- If the change cannot be made, find out more information.
IF (@@ROWCOUNT = 0)
BEGIN
    -- Obtain the complete change information for the row.
    SELECT
        CT.SYS_CHANGE_VERSION, CT.SYS_CHANGE_CREATION_VERSION,
        CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS
    FROM
        CHANGETABLE(CHANGES SalesLT.Product, @last_sync_version) AS CT
    WHERE
        CT.ProductID = @product_id;

    -- Check CT.SYS_CHANGE_VERSION to verify that it really was a conflict.
    -- Check CT.SYS_CHANGE_OPERATION to determine the type of conflict:
    -- update-update or update-delete.
    -- The row that is specified by @product_id might no longer exist 
    -- if it has been deleted.
END

Настройка сведений о контексте

С помощью предложения WITH CHANGE_TRACKING_CONTEXT приложение может хранить контекстные данные вместе с информацией об изменениях. Затем эти данные можно получить в столбце SYS_CHANGE_CONTEXT, который возвращает функция CHANGETABLE(CHANGES ...).

Контекстные данные обычно используются для определения источника изменений. Если источник изменений можно определить, эти данные могут использоваться хранилищем данных, чтобы не получать изменения при повторной синхронизации.

-- Try to update the row and check for a conflict.
WITH CHANGE_TRACKING_CONTEXT (@source_id)
UPDATE
  SalesLT.Product
SET
  ListPrice = @new_listprice
FROM
  SalesLT.Product AS P
WHERE
  ProductID = @product_id AND
    @last_sync_version >= ISNULL (
    (SELECT CT.SYS_CHANGE_VERSION FROM CHANGETABLE(VERSION SalesLT.Product,
    (ProductID), (P.ProductID)) AS CT),
       0);

Обеспечение согласованности и правильности результатов

Приложение должно учитывать процесс очистки при проверке значения параметра @last_sync_version. Это объясняется тем, что данные могли быть удалены после вызова функции CHANGE_TRACKING_MIN_VALID_VERSION(), но перед тем, как было выполнено обновление.

Следует использовать изоляцию моментальных снимков и вносить изменения в транзакцию моментального снимка.

-- Prerequisite is to ensure ALLOW_SNAPSHOT_ISOLATION is ON for the database.

SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN
    -- Verify that last_sync_version is valid.
    IF (@last_sync_version <
CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('SalesLT.Product')))
    BEGIN
       RAISERROR (N'Last_sync_version too old', 16, -1);
    END
    ELSE
    BEGIN
        -- Try to update the row.
        -- Check @@ROWCOUNT and check for a conflict.
    END;
COMMIT TRAN;

Заметка

Существует вероятность того, что обновляемая в рамках транзакции моментальных снимков строка уже была обновлена в другой транзакции после начала транзакции моментальных снимков. В этом случае произойдет конфликт обновления при изоляции моментальных снимков, который вызовет прекращение транзакции. В этом случае повторите попытку обновления. В дальнейшем это приведет к обнаружению конфликта отслеживания изменений и ни одна из строк обновлена не будет.

Отслеживание изменений и восстановление данных

Приложения, для которых необходима синхронизация, должны учитывать возможность восстановления базы данных, для которой включено отслеживание изменений, в предыдущее состояние. Это может произойти после восстановления базы данных из резервной копии, при отработке отказа в асинхронное зеркальное отображение базы данных или при использовании доставки журналов. Эту проблему иллюстрирует следующий сценарий.

  1. Таблица T1 отслеживается, а минимальная допустимая версия таблицы — 50.

  2. Клиентское приложение синхронизирует данные версии 100 и получает все данные отслеживания изменений, произведенных с версии 50 до версии 100.

  3. После версии 100 в таблицу Т1 были внесены дополнительные изменения.

  4. В версии 120 возникает сбой, а администратор базы данных восстанавливает базу данных с потерей данных. После завершения восстановления таблица содержит данные до версии 70, а минимальная синхронизированная версия по-прежнему равна 50.

    Это означает, что синхронизированное хранилище данных содержит данные, которых уже нет в первичном хранилище.

  5. Таблица Т1 обновлялась многократно. Текущий номер версии для нее — 130.

  6. Клиентское приложение синхронизируется вновь и получает номер последней синхронизации 100. Проверка этого номера клиентом происходит успешно, так как 100 больше 50.

    Клиент получает изменения между версиями 100 и 130. На этом этапе клиент не знает, что изменения в диапазоне от 70 до 100 не совпадают с ранее. Данные на клиенте и сервере не синхронизируются.

Если база данных была восстановлена до точки после версии 100, не будет проблем с синхронизацией. Клиент и сервер должны правильно синхронизировать данные во время следующего интервала синхронизации.

Отслеживание изменений не обеспечивает поддержку восстановления после потери данных. Однако существует две возможности обнаружения проблем синхронизации такого рода.

  • Сохраните идентификатор версии базы данных на сервере и обновляйте это значение при каждом восстановлении данных или их потере, вызванной любыми другими причинами. Этот идентификатор должно хранить и проверять во время синхронизации данных каждое клиентское приложение. Если происходит потеря данных, идентификаторы не будут совпадать, и клиенты будут повторно инициализировать. Один из недостатков заключается в том, что потеря данных не пересекла последнюю синхронизированную границу, клиент может сделать ненужную повторную инициализацию.

  • Когда клиент делает запрос об изменениях, сохраните номер последней версии синхронизации каждого клиента сервера. Если возникла проблема с данными, последние синхронизированные номера версий не совпадают. Это будет означать, что необходима повторная инициализация.

См. также