Bekerja dengan pelacakan perubahan (SQL Server)

Berlaku untuk:SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

Aplikasi yang menggunakan pelacakan perubahan harus dapat memperoleh perubahan terlacak, menerapkan perubahan ini ke penyimpanan data lain, dan memperbarui database sumber. Artikel ini menjelaskan cara melakukan tugas-tugas ini, dan juga pelacakan perubahan peran diputar ketika failover terjadi dan database harus dipulihkan dari cadangan.

Mendapatkan perubahan dengan menggunakan fungsi pelacakan perubahan

Menjelaskan cara menggunakan fungsi pelacakan perubahan untuk mendapatkan perubahan dan informasi tentang perubahan yang dibuat pada database.

Tentang fungsi pelacakan perubahan

Aplikasi dapat menggunakan fungsi berikut untuk mendapatkan perubahan yang dibuat dalam database dan informasi tentang perubahan:

Fungsi CHANGETABLE(CHANGES ...)
Fungsi kumpulan baris ini digunakan untuk mengkueri informasi perubahan. Fungsi mengkueri data yang disimpan dalam tabel pelacakan perubahan internal. Fungsi menghasilkan tataan hasil yang berisi kunci primer baris yang telah diubah bersama dengan informasi perubahan lainnya seperti operasi, kolom yang diperbarui, dan versi untuk baris tersebut.

CHANGETABLE(CHANGES ...) mengambil versi sinkronisasi terakhir sebagai argumen. Versi sinkronisasi terakhir diperoleh dengan menggunakan variabel @last_synchronization_version. Semantik versi sinkronisasi terakhir adalah sebagai berikut:

  • Klien panggilan telah memperoleh perubahan dan mengetahui tentang semua perubahan hingga dan termasuk versi sinkronisasi terakhir.

  • CHANGETABLE(CHANGES ...) oleh karena itu akan mengembalikan semua perubahan yang telah terjadi setelah versi sinkronisasi terakhir.

    Ilustrasi berikut menunjukkan bagaimana CHANGETABLE(CHANGE ...) digunakan untuk mendapatkan perubahan.

    Diagram that shows an example of change tracking query output.

    Dalam contoh ini, Klien A terakhir disinkronkan pada pukul 09.30, sementara Klien B terakhir disinkronkan pada pukul 10.30. Pada pukul 10.00 dan sekali lagi pada pukul 11.00, beberapa perubahan dilakukan pada data. Perubahan terlacak ini dirangkum di bawah ini.

    CHANGETABLE(CHANGE...) Output - 11.30

    Klien A terakhir disinkronkan pada pukul 09.30.

    ID produk Operasi Kolom
    139 Pembaruan Nama, Harga
    140 Hapus -
    141 Sisipkan -

    Klien B terakhir disinkronkan pada pukul 10.30.

    ID produk Operasi Kolom
    139 Pembaruan Harga
    140 Hapus -
    141 Pembaruan Harga

Fungsi CHANGE_TRACKING_CURRENT_VERSION()
Digunakan untuk mendapatkan versi saat ini yang akan digunakan saat berikutnya saat mengkueri perubahan. Versi ini mewakili versi transaksi yang diterapkan terakhir.

Fungsi CHANGE_TRACKING_MIN_VALID_VERSION()
Digunakan untuk mendapatkan versi valid minimum yang dapat dimiliki klien dan masih mendapatkan hasil yang valid dari CHANGETABLE(). Klien harus memeriksa versi sinkronisasi terakhir terhadap nilai yang dihasilkan oleh fungsi ini. Jika versi sinkronisasi terakhir kurang dari versi yang dihasilkan oleh fungsi ini, klien tidak akan dapat memperoleh hasil yang valid dari CHANGETABLE() dan harus menginisialisasi ulang.

Mendapatkan data awal

Sebelum aplikasi dapat memperoleh perubahan untuk pertama kalinya, aplikasi harus mengirim kueri untuk mendapatkan data awal dan versi sinkronisasi. Aplikasi harus mendapatkan data yang sesuai langsung dari tabel, lalu menggunakan CHANGE_TRACKING_CURRENT_VERSION() untuk mendapatkan versi awal. Versi ini akan diteruskan ke CHANGETABLE(CHANGES ...) saat pertama kali perubahan diperoleh.

Contoh berikut menunjukkan cara mendapatkan versi sinkronisasi awal dan himpunan data awal.

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;

Menggunakan fungsi pelacakan perubahan untuk mendapatkan perubahan

Untuk mendapatkan baris yang diubah untuk tabel dan informasi tentang perubahan, gunakan CHANGETABLE(CHANGES...). Misalnya, kueri berikut mendapatkan perubahan untuk SalesLT.Product tabel.

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;

Biasanya, klien ingin mendapatkan data terbaru untuk satu baris, bukan hanya kunci primer untuk baris tersebut. Oleh karena itu, aplikasi akan menggabungkan hasil dari CHANGETABLE(CHANGES ...) dengan data di tabel pengguna. Misalnya, kueri berikut bergabung dengan tabel SalesLT.Product untuk mendapatkan nilai untuk kolom Name dan ListPrice. Perhatikan penggunaan OUTER JOIN. Hal ini diperlukan untuk memastikan bahwa informasi perubahan ditampilkan untuk baris-baris yang telah dihapus dari tabel pengguna.

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;

Untuk mendapatkan versi untuk digunakan dalam enumerasi perubahan berikutnya, gunakan CHANGE_TRACKING_CURRENT_VERSION(), seperti yang ditunjukkan dalam contoh berikut.

SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();

Ketika aplikasi mendapatkan perubahan, aplikasi harus menggunakan CHANGETABLE(CHANGES...) dan CHANGE_TRACKING_CURRENT_VERSION(), seperti yang ditunjukkan dalam contoh berikut.

-- 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;

Nomor versi

Database yang mengaktifkan pelacakan perubahan memiliki penghitung versi yang meningkat saat perubahan dilakukan untuk mengubah tabel terlacak. Setiap baris yang diubah memiliki nomor versi yang terkait dengannya. Saat permintaan dikirim ke aplikasi untuk meminta perubahan, fungsi disebut yang menyediakan nomor versi. Fungsi mengembalikan informasi tentang semua perubahan yang telah dibuat sejak versi tersebut. Dalam beberapa cara, versi pelacakan perubahan mirip dalam konsep dengan jenis data rowversion .

Memvalidasi versi terakhir yang disinkronkan

Informasi tentang perubahan dipertahankan untuk waktu yang terbatas. Lamanya waktu dikontrol oleh parameter CHANGE_RETENTION yang dapat ditentukan sebagai bagian dari ALTER DATABASE.

Waktu yang ditentukan untuk CHANGE_RETENTION menentukan seberapa sering semua aplikasi harus meminta perubahan dari database. Jika aplikasi memiliki nilai untuk last_synchronization_version yang lebih lama dari versi sinkronisasi minimum yang valid untuk tabel, aplikasi tersebut tidak dapat melakukan enumerasi perubahan yang valid. Ini karena beberapa informasi perubahan mungkin telah dibersihkan. Sebelum aplikasi mendapatkan perubahan dengan menggunakan CHANGETABLE(CHANGE ...), aplikasi harus memvalidasi nilai untuk last_synchronization_version bahwa aplikasi berencana untuk meneruskan ke CHANGETABLE(CHANGE ...). Jika nilai last_synchronization_version tidak valid, aplikasi tersebut harus menginisialisasi ulang semua data.

Contoh berikut menunjukkan cara memverifikasi validitas nilai last_synchronization_version untuk setiap tabel.

-- 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;

Seperti yang ditunjukkan contoh berikut, validitas nilai last_synchronization_version dapat diperiksa terhadap semua tabel dalam database.

-- 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;

Menggunakan pelacakan kolom

Pelacakan kolom memungkinkan aplikasi untuk mendapatkan data hanya untuk kolom yang telah berubah alih-alih seluruh baris. Misalnya, pertimbangkan skenario di mana tabel memiliki satu atau beberapa kolom yang besar, tetapi jarang berubah; dan juga memiliki kolom lain yang sering berubah. Tanpa pelacakan kolom, aplikasi hanya dapat menentukan bahwa baris telah berubah dan harus menyinkronkan semua data yang menyertakan data kolom besar. Namun, dengan menggunakan pelacakan kolom, aplikasi dapat menentukan apakah data kolom besar berubah dan hanya menyinkronkan data jika telah berubah.

Informasi pelacakan kolom muncul di kolom SYS_CHANGE_COLUMNS yang dikembalikan oleh fungsi CHANGETABLE(CHANGES ...).

Pelacakan kolom dapat digunakan sehingga NULL dikembalikan untuk kolom yang belum berubah. Jika kolom dapat diubah menjadi NULL, kolom terpisah harus dikembalikan untuk menunjukkan apakah kolom berubah.

Dalam contoh berikut, CT_ThumbnailPhoto kolom akan menjadi NULL jika kolom tersebut tidak berubah. Kolom ini juga bisa karena NULL diubah menjadi NULL - aplikasi dapat menggunakan CT_ThumbNailPhoto_Changed kolom untuk menentukan apakah kolom berubah.

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';

Dapatkan hasil yang konsisten dan benar

Mendapatkan data yang diubah untuk tabel memerlukan beberapa langkah. Hasil yang tidak konsisten atau salah dapat dikembalikan jika masalah tertentu tidak dipertimbangkan dan ditangani.

Misalnya, untuk mendapatkan perubahan yang dibuat pada Sales tabel dan SalesOrders tabel, aplikasi akan melakukan langkah-langkah berikut:

  1. Validasi versi terakhir yang disinkronkan dengan menggunakan CHANGE_TRACKING_MIN_VALID_VERSION().

  2. Dapatkan versi yang dapat digunakan untuk mendapatkan perubahan lain kali dengan menggunakan CHANGE_TRACKING_CURRENT_VERSION().

  3. Dapatkan perubahan untuk Sales tabel dengan menggunakan CHANGETABLE(CHANGE ...).

  4. Dapatkan perubahan untuk SalesOrders tabel dengan menggunakan CHANGETABLE(CHANGE ...).

Dua proses terjadi dalam database yang dapat memengaruhi hasil yang dikembalikan oleh langkah-langkah sebelumnya:

  • Proses pembersihan berjalan di latar belakang dan menghapus informasi pelacakan perubahan yang lebih lama dari periode retensi yang ditentukan.

    Proses pembersihan adalah proses latar belakang terpisah yang menggunakan periode retensi yang ditentukan saat Anda mengonfigurasi pelacakan perubahan untuk database. Masalahnya adalah bahwa proses pembersihan dapat terjadi pada waktu antara ketika versi sinkronisasi terakhir divalidasi dan ketika panggilan ke CHANGETABLE(CHANGES...) dilakukan. Versi sinkronisasi terakhir yang valid mungkin tidak lagi valid pada saat perubahan diambil. Oleh karena itu, hasil yang salah mungkin dikembalikan.

  • Operasi DML yang sedang berlangsung terjadi dalam Penjualan dan SalesOrders tabel, seperti operasi berikut:

    • Perubahan dapat dilakukan pada tabel setelah versi untuk waktu berikutnya telah diperoleh dengan menggunakan CHANGE_TRACKING_CURRENT_VERSION(). Oleh karena itu, lebih banyak perubahan dapat dikembalikan dari yang diharapkan.

    • Transaksi dapat diterapkan dalam waktu antara panggilan untuk mengambil perubahan dari Sales tabel dan panggilan untuk mengambil perubahan dari SalesOrders tabel. Oleh karena itu, hasil untuk SalesOrder tabel dapat memiliki nilai kunci asing yang tidak ada dalam Sales tabel.

Untuk mengatasi tantangan yang tercantum sebelumnya, kami sarankan Anda menggunakan isolasi rekam jepret. Ini akan membantu memastikan konsistensi informasi perubahan dan menghindari kondisi balapan yang terkait dengan tugas pembersihan latar belakang. Jika Anda tidak menggunakan transaksi rekam jepret, mengembangkan aplikasi yang menggunakan pelacakan perubahan dapat memerlukan lebih banyak upaya secara signifikan.

Menggunakan isolasi rekam jepret

Pelacakan perubahan telah dirancang untuk bekerja dengan baik dengan isolasi rekam jepret. Isolasi rekam jepret harus diaktifkan untuk database. Semua langkah yang diperlukan untuk mendapatkan perubahan harus disertakan di dalam transaksi rekam jepret. Ini akan memastikan bahwa semua perubahan yang dilakukan pada data saat mendapatkan perubahan tidak akan terlihat oleh kueri di dalam transaksi rekam jepret.

Untuk mendapatkan data di dalam transaksi rekam jepret, lakukan langkah-langkah berikut:

  1. Atur tingkat isolasi transaksi ke rekam jepret dan mulai transaksi.

  2. Validasi versi sinkronisasi terakhir dengan menggunakan CHANGE_TRACKING_MIN_VALID_VERSION().

  3. Dapatkan versi yang akan digunakan lain kali dengan menggunakan CHANGE_TRACKING_CURRENT_VERSION().

  4. Dapatkan perubahan untuk Sales tabel dengan menggunakan CHANGETABLE(CHANGE ...)

  5. Dapatkan perubahan untuk SalesOrders tabel dengan menggunakan CHANGETABLE(CHANGE ...)

  6. Terapkan transaksi.

Beberapa poin yang perlu diingat karena semua langkah untuk mendapatkan perubahan ada di dalam transaksi rekam jepret:

  • Jika pembersihan terjadi setelah versi sinkronisasi terakhir divalidasi, hasil dari CHANGETABLE(CHANGES ...) masih akan valid karena operasi penghapusan yang dilakukan oleh pembersihan tidak akan terlihat di dalam transaksi.

  • Setiap perubahan yang dilakukan pada Sales tabel atau SalesOrders tabel setelah versi sinkronisasi berikutnya diperoleh tidak akan terlihat, dan panggilan ke CHANGETABLE(CHANGES ...) tidak akan pernah mengembalikan perubahan dengan versi yang lebih baru dari yang dikembalikan oleh CHANGE_TRACKING_CURRENT_VERSION(). Konsistensi antara Sales tabel dan SalesOrders tabel juga akan dipertahankan, karena transaksi yang dilakukan dalam waktu antara panggilan ke CHANGETABLE(CHANGE ...) tidak akan terlihat.

Contoh berikut menunjukkan bagaimana isolasi rekam jepret diaktifkan untuk database.

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

Transaksi rekam jepret digunakan sebagai berikut:

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

Untuk informasi selengkapnya tentang transaksi rekam jepret, lihat MENGATUR TINGKAT ISOLASI TRANSAKSI (Transact-SQL).

Pembersihan dan isolasi rekam jepret

Mengaktifkan isolasi rekam jepret dan pelacakan perubahan pada database yang sama, atau pada dua database yang berbeda dalam instans yang sama dapat mengakibatkan proses pembersihan meninggalkan baris kedaluwarsa ketika sys.syscommittab ada transaksi terbuka dalam database dengan isolasi rekam jepret. Ini dapat terjadi karena proses pembersihan pelacakan perubahan mengambil tanda air rendah di seluruh instans (yang merupakan versi pembersihan yang aman) untuk diperhitungkan saat melakukan pembersihan. Ini dilakukan untuk memastikan proses pembersihan otomatis pelacakan perubahan tidak menghapus baris apa pun yang mungkin diperlukan oleh transaksi terbuka dalam database yang mengaktifkan isolasi rekam jepret. Terus baca isolasi rekam jepret yang diterapkan, dan transaksi isolasi rekam jepret sesingkat mungkin untuk memastikan baris yang kedaluwarsa dibersihkan sys.syscommittab tepat waktu.

Alternatif untuk isolasi rekam jepret

Ada alternatif untuk menggunakan isolasi rekam jepret, tetapi memerlukan lebih banyak pekerjaan untuk memastikan semua persyaratan aplikasi terpenuhi. Untuk memastikan last_synchronization_version valid dan data tidak dihapus oleh proses pembersihan sebelum perubahan diperoleh, ikuti langkah-langkah berikut:

  1. Periksa last_synchronization_version setelah panggilan ke CHANGETABLE().

  2. Periksa last_synchronization_version sebagai bagian dari setiap kueri untuk mendapatkan perubahan dengan menggunakan CHANGETABLE().

Perubahan dapat terjadi setelah versi sinkronisasi untuk enumerasi berikutnya telah diperoleh. Ada dua cara untuk menangani situasi ini. Opsi yang digunakan tergantung pada aplikasi dan bagaimana ia dapat menangani efek samping dari setiap pendekatan:

  • Abaikan perubahan yang memiliki versi lebih besar dari versi sinkronisasi baru.

    Pendekatan ini memiliki efek samping bahwa baris baru atau yang diperbarui akan dilewati jika dibuat atau diperbarui sebelum versi sinkronisasi baru, tetapi kemudian diperbarui setelahnya. Jika ada baris baru, masalah integritas referensial mungkin terjadi jika ada baris dalam tabel lain yang dibuat yang mereferensikan baris yang dilewati. Jika ada baris yang sudah diperbarui, baris akan dilewati dan tidak disinkronkan hingga waktu berikutnya.

  • Sertakan semua perubahan, bahkan yang memiliki versi lebih besar dari versi sinkronisasi baru.

    Baris yang memiliki versi lebih besar dari versi sinkronisasi baru akan diperoleh lagi pada sinkronisasi berikutnya. Ini harus diharapkan dan ditangani oleh aplikasi.

Selain dua opsi sebelumnya, Anda dapat merancang pendekatan yang menggabungkan kedua opsi, tergantung pada operasi. Misalnya, Anda mungkin ingin aplikasi yang terbaik untuk mengabaikan perubahan yang lebih baru dari versi sinkronisasi berikutnya di mana baris dibuat atau dihapus, tetapi pembaruan tidak diabaikan.

Catatan

Memilih pendekatan yang akan berfungsi untuk aplikasi saat Anda menggunakan pelacakan perubahan (atau mekanisme pelacakan kustom apa pun), memerlukan analisis yang signifikan. Oleh karena itu, jauh lebih mudah untuk menggunakan isolasi rekam jepret.

Cara pelacakan perubahan menangani perubahan pada database

Beberapa aplikasi yang menggunakan pelacakan perubahan melakukan sinkronisasi dua arah dengan penyimpanan data lain. Artinya, perubahan yang dilakukan dalam database SQL Server diperbarui di penyimpanan data lain, dan perubahan yang dilakukan di penyimpanan lain diperbarui dalam database SQL Server.

Saat aplikasi memperbarui database lokal dengan perubahan dari penyimpanan data lain, aplikasi harus melakukan operasi berikut:

  • Periksa konflik.

    Konflik terjadi ketika data yang sama diubah pada saat yang sama di kedua penyimpanan data. Aplikasi harus dapat memeriksa konflik dan mendapatkan informasi yang cukup untuk memungkinkan konflik diselesaikan.

  • Simpan informasi konteks aplikasi.

    Aplikasi menyimpan data yang memiliki informasi pelacakan perubahan. Informasi ini akan tersedia bersama dengan informasi pelacakan perubahan lainnya ketika perubahan diperoleh dari database lokal. Contoh umum dari informasi kontekstual ini adalah pengidentifikasi untuk penyimpanan data yang merupakan sumber perubahan.

Untuk melakukan operasi sebelumnya, aplikasi sinkronisasi dapat menggunakan fungsi berikut:

  • CHANGETABLE(VERSION...)

    Ketika aplikasi membuat perubahan, aplikasi dapat menggunakan fungsi ini untuk memeriksa konflik. Fungsi ini mendapatkan informasi pelacakan perubahan terbaru untuk baris tertentu dalam tabel terlacak perubahan. Informasi pelacakan perubahan menyertakan versi baris yang terakhir diubah. Informasi ini memungkinkan aplikasi untuk menentukan apakah baris diubah setelah terakhir kali aplikasi disinkronkan.

  • DENGAN CHANGE_TRACKING_CONTEXT

    Aplikasi dapat menggunakan klausa ini untuk menyimpan data konteks.

Periksa konflik

Dalam skenario sinkronisasi dua arah, aplikasi klien harus menentukan apakah baris belum diperbarui sejak aplikasi terakhir kali mendapatkan perubahan.

Contoh berikut menunjukkan cara menggunakan fungsi CHANGETABLE(VERSION ...) untuk memeriksa konflik dengan cara yang paling efisien, tanpa kueri terpisah. Dalam contoh, CHANGETABLE(VERSION ...) menentukan SYS_CHANGE_VERSION untuk baris yang ditentukan oleh @product id. CHANGETABLE(CHANGES ...) dapat memperoleh informasi yang sama, tetapi itu akan kurang efisien. Jika nilai SYS_CHANGE_VERSION untuk baris lebih besar dari @last_sync_versionnilai , ada konflik. Jika ada konflik, baris tidak akan diperbarui. ISNULL() Pemeriksaan diperlukan karena mungkin tidak ada informasi perubahan yang tersedia untuk baris tersebut. Tidak ada informasi perubahan yang akan ada jika baris belum diperbarui sejak pelacakan perubahan diaktifkan atau karena informasi perubahan dibersihkan.

-- 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);

Kode berikut dapat memeriksa jumlah baris yang diperbarui dan dapat mengidentifikasi informasi selengkapnya tentang konflik.

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

Mengatur informasi konteks

Dengan menggunakan klausa WITH CHANGE_TRACKING_CONTEXT, aplikasi dapat menyimpan informasi konteks bersama dengan informasi perubahan. Informasi ini kemudian dapat diperoleh dari kolom SYS_CHANGE_CONTEXT yang dikembalikan oleh CHANGETABLE(CHANGE ...).

Informasi konteks biasanya digunakan untuk mengidentifikasi sumber perubahan. Jika sumber perubahan dapat diidentifikasi, informasi tersebut dapat digunakan oleh penyimpanan data untuk menghindari perolehan perubahan saat disinkronkan lagi.

-- 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);

Memastikan hasil yang konsisten dan benar

Aplikasi harus mempertimbangkan proses pembersihan ketika memvalidasi nilai @last_sync_version. Ini karena data dapat dihapus setelah CHANGE_TRACKING_MIN_VALID_VERSION() dipanggil, tetapi sebelum pembaruan dibuat.

Anda harus menggunakan isolasi rekam jepret dan membuat perubahan dalam transaksi rekam jepret.

-- 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;

Catatan

Ada kemungkinan bahwa baris yang diperbarui dalam transaksi rekam jepret dapat diperbarui dalam transaksi lain setelah transaksi rekam jepret dimulai. Dalam hal ini, konflik pembaruan isolasi rekam jepret akan terjadi dan menyebabkan transaksi dihentikan. Jika ini terjadi, coba lagi pembaruan. Ini kemudian akan menyebabkan konflik pelacakan perubahan terdeteksi dan tidak ada baris yang diubah.

Pelacakan perubahan dan pemulihan data

Aplikasi yang memerlukan sinkronisasi harus mempertimbangkan kasus di mana database yang mengaktifkan pelacakan perubahan kembali ke versi data yang lebih lama. Ini dapat terjadi setelah database dipulihkan dari cadangan, ketika ada failover ke cermin database asinkron, atau ketika ada kegagalan saat menggunakan pengiriman log. Skenario berikut mengilustrasikan masalah:

  1. Tabel T1 dilacak perubahan, dan versi minimum yang valid untuk tabel adalah 50.

  2. Aplikasi klien menyinkronkan data pada versi 100 dan mendapatkan informasi tentang semua perubahan antara versi 50 dan 100.

  3. Perubahan tambahan dilakukan pada tabel T1 setelah versi 100.

  4. Pada versi 120, ada kegagalan dan administrator database memulihkan database dengan kehilangan data. Setelah operasi pemulihan, tabel berisi data hingga versi 70, dan versi minimum yang disinkronkan masih 50.

    Ini berarti bahwa penyimpanan data yang disinkronkan memiliki data yang tidak lagi ada di penyimpanan data utama.

  5. T1 diperbarui berkali-kali. Ini membawa versi saat ini ke 130.

  6. Aplikasi klien menyinkronkan lagi dan memasok versi terakhir yang disinkronkan dari 100. Klien berhasil memvalidasi nomor ini karena 100 lebih besar dari 50.

    Klien memperoleh perubahan antara versi 100 dan 130. Pada titik ini, klien tidak menyadari bahwa perubahan antara 70 dan 100 tidak sama seperti sebelumnya. Data di klien dan server tidak disinkronkan.

Jika database dipulihkan ke titik setelah versi 100, tidak akan ada masalah dengan sinkronisasi. Klien dan server akan menyinkronkan data dengan benar selama interval sinkronisasi berikutnya.

Pelacakan perubahan tidak memberikan dukungan untuk pemulihan dari hilangnya data. Namun, ada dua opsi untuk mendeteksi jenis masalah sinkronisasi ini:

  • Simpan ID versi database di server, dan perbarui nilai ini setiap kali database dipulihkan atau kehilangan data. Setiap aplikasi klien akan menyimpan ID, dan setiap klien harus memvalidasi ID ini saat menyinkronkan data. Jika kehilangan data terjadi, ID tidak akan cocok dan klien akan menginisialisasi ulang. Salah satu kelemahannya adalah jika kehilangan data tidak melewati batas terakhir yang disinkronkan, klien mungkin melakukan reinisialisasi yang tidak perlu.

  • Saat klien meminta perubahan, rekam nomor versi sinkronisasi terakhir untuk setiap klien di server. Jika ada masalah dengan data, nomor versi terakhir yang disinkronkan tidak akan cocok. Ini menunjukkan bahwa diperlukan reinisialisasi.

Baca juga