Dela via


Arbeta med ändringsspårning (SQL Server)

Gäller för:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceSQL-databas i Förhandsversion av Microsoft Fabric

Program som använder ändringsspårning måste kunna hämta spårade ändringar, tillämpa ändringarna på ett annat datalager och uppdatera källdatabasen. Den här artikeln beskriver hur du utför dessa uppgifter, och även vilken roll ändringsspårningen spelar när en redundansväxling inträffar och en databas måste återställas från en säkerhetskopia.

Hämta ändringar med hjälp av ändringsspårningsfunktioner

Beskriver hur du använder funktionerna för ändringsspårning för att hämta ändringar och information om de ändringar som har gjorts i en databas.

Om funktionerna för ändringsspårning

Program kan använda följande funktioner för att hämta de ändringar som görs i en databas och information om ändringarna:

  • CHANGETABLE(CHANGES ...) funktion

    Den här raduppsättningsfunktionen används för att fråga efter ändringsinformation. Funktionen frågar efter data som lagras i de interna ändringsspårningstabellerna. Funktionen returnerar en resultatuppsättning som innehåller de primära nycklarna för rader som har ändrats tillsammans med annan ändringsinformation, till exempel åtgärden, uppdaterade kolumner och version för raden.

    CHANGETABLE(CHANGES ...) tar en senaste synkroniseringsversion som argument. Den senaste synkroniseringsversionen hämtas med hjälp av variabeln @last_synchronization_version . Semantiken för den senaste synkroniseringsversionen är följande:

  • Den anropande klienten har fått ändringar och känner till alla ändringar fram till och med den senaste synkroniseringsversionen.

  • CHANGETABLE(CHANGES ...) returnerar därför alla ändringar som har inträffat efter den senaste synkroniseringsversionen.

Följande bild visar hur CHANGETABLE(CHANGES ...) används för att hämta ändringar.

Diagram som visar ett exempel på frågeutdata för ändringsspårning.

I det här exemplet synkroniserades klient A senast kl. 09:30, medan klient B senast synkroniserades kl. 10:30. Klockan 10:00 och igen klockan 11:00 gjordes flera ändringar i data. Dessa spårade ändringar sammanfattas i följande exempel.

CHANGETABLE(CHANGES...) Utdata – 11:30

Klient A synkroniserades senast kl. 09:30.

Product ID Verksamhet Columns
139 Update Namn, pris
140 Ta bort -
141 Infoga -

Klient B synkroniserades senast kl. 10:30.

Product ID Verksamhet Columns
139 Update Pris
140 Ta bort -
141 Update Pris
  • CHANGE_TRACKING_CURRENT_VERSION() funktion

    Används för att hämta den aktuella versionen som ska användas nästa gång du frågar efter ändringar. Den här versionen representerar versionen av den senast genomförda transaktionen.

  • CHANGE_TRACKING_MIN_VALID_VERSION() funktion

    Används för att hämta den lägsta giltiga versionen som en klient kan ha och fortfarande få giltiga resultat från CHANGETABLE(). Klienten bör kontrollera den senaste synkroniseringsversionen mot det värde som returneras av den här funktionen. Om den senaste synkroniseringsversionen är mindre än den version som returneras av den här funktionen kan klienten inte hämta giltiga resultat från CHANGETABLE() och måste initiera om.

Hämta initiala data

Innan ett program kan hämta ändringar för första gången måste programmet skicka en fråga för att hämta de första data och synkroniseringsversionen. Programmet måste hämta lämpliga data direkt från tabellen och sedan använda CHANGE_TRACKING_CURRENT_VERSION() för att hämta den ursprungliga versionen. Den här versionen skickas till CHANGETABLE(CHANGES ...) första gången som ändringar hämtas.

I följande exempel visas hur du hämtar den första synkroniseringsversionen och den första datauppsättningen.

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;

Använda funktionerna för ändringsspårning för att hämta ändringar

Om du vill hämta de ändrade raderna för en tabell och information om ändringarna använder du CHANGETABLE(CHANGES...). Följande fråga hämtar till exempel ändringar för SalesLT.Product tabellen.

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;

Vanligtvis vill en klient hämta de senaste data för en rad i stället för endast de primära nycklarna för raden. Därför skulle ett program koppla resultaten från CHANGETABLE(CHANGES ...) med data i användartabellen. Följande fråga ansluter till exempel till SalesLT.Product tabellen för att hämta värdena för kolumnerna Name och ListPrice . Observera användningen av OUTER JOIN. Detta krävs för att se till att ändringsinformationen returneras för de rader som har tagits bort från användartabellen.

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;

Om du vill hämta versionen för användning i nästa ändringsuppräkning använder du CHANGE_TRACKING_CURRENT_VERSION(), som du ser i följande exempel.

SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();

När ett program får ändringar måste det använda både CHANGETABLE(CHANGES...) och CHANGE_TRACKING_CURRENT_VERSION(), enligt följande exempel.

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

Versionsnummer

En databas som har aktiverat ändringsspårning har en versionsräknare som ökar när ändringar görs i spårade tabeller. Varje ändrad rad har ett versionsnummer som är associerat med den. När en begäran skickas till ett program för att fråga efter ändringar anropas en funktion som tillhandahåller ett versionsnummer. Funktionen returnerar information om alla ändringar som har gjorts sedan den versionen. På sätt och vis liknar ändringsspårningsversionen i begreppet datatypen rowversion .

Verifiera den senaste synkroniserade versionen

Information om ändringar behålls under en begränsad tid. Tidslängden styrs av parametern CHANGE_RETENTION som kan anges som en del av ALTER DATABASE.

Den angivna tiden avgör CHANGE_RETENTION hur ofta alla program måste begära ändringar från databasen. Om ett program har ett värde för last_synchronization_version som är äldre än den lägsta giltiga synkroniseringsversionen för en tabell kan programmet inte utföra en giltig ändringsuppräkning. Det beror på att viss ändringsinformation kan ha rensats. Innan ett program får ändringar med hjälp CHANGETABLE(CHANGES ...)av måste programmet verifiera värdet för last_synchronization_version det som det planerar att skicka till CHANGETABLE(CHANGES ...). Om värdet last_synchronization_version för inte är giltigt måste programmet initiera alla data igen.

I följande exempel visas hur du verifierar giltigheten för värdet last_synchronization_version för för varje tabell.

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

Som följande exempel visar kan värdets last_synchronization_version giltighet kontrolleras mot alla tabeller i databasen.

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

Använda kolumnspårning

Med kolumnspårning kan program endast hämta data för de kolumner som har ändrats i stället för hela raden. Tänk till exempel på scenariot där en tabell har en eller flera kolumner som är stora, men som sällan ändras. och har även andra kolumner som ofta ändras. Utan kolumnspårning kan ett program bara fastställa att en rad har ändrats och måste synkronisera alla data som innehåller stora kolumndata. Genom att använda kolumnspårning kan ett program dock avgöra om stora kolumndata har ändrats och endast synkronisera data om de har ändrats.

Information om kolumnspårning visas i kolumnen SYS_CHANGE_COLUMNS som returneras av CHANGETABLE(CHANGES ...) funktionen.

Kolumnspårning kan användas så att NULL den returneras för en kolumn som inte har ändrats. Om kolumnen kan ändras till NULLmåste en separat kolumn returneras för att ange om kolumnen har ändrats.

I följande exempel CT_ThumbnailPhoto blir NULL kolumnen om kolumnen inte ändrades. Den här kolumnen kan också bero NULL på att den har ändrats till NULL. Programmet kan använda CT_ThumbNailPhoto_Changed kolumnen för att avgöra om kolumnen har ändrats.

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

Få konsekventa och korrekta resultat

Det krävs flera steg för att hämta ändrade data för en tabell. Inkonsekventa eller felaktiga resultat kan returneras om vissa problem inte beaktas och hanteras.

För att till exempel hämta de ändringar som har gjorts i en Sales tabell och SalesOrders tabell utför ett program följande steg:

  1. Verifiera den senaste synkroniserade versionen med hjälp CHANGE_TRACKING_MIN_VALID_VERSION()av .

  2. Hämta den version som kan användas för att hämta ändringar nästa gång med hjälp CHANGE_TRACKING_CURRENT_VERSION()av .

  3. Hämta ändringarna för Sales tabellen med hjälp CHANGETABLE(CHANGES ...)av .

  4. Hämta ändringarna för SalesOrders tabellen med hjälp CHANGETABLE(CHANGES ...)av .

Två processer förekommer i databasen som kan påverka de resultat som returneras av föregående steg:

  • Rensningsprocessen körs i bakgrunden och tar bort information om ändringsspårning som är äldre än den angivna kvarhållningsperioden.

    Rensningsprocessen är en separat bakgrundsprocess som använder kvarhållningsperioden som anges när du konfigurerar ändringsspårning för databasen. Problemet är att rensningsprocessen kan inträffa under tiden mellan när den senaste synkroniseringsversionen verifierades och när anropet till CHANGETABLE(CHANGES...) görs. En senaste synkroniseringsversion som var giltig kanske inte längre är giltig när ändringarna hämtas. Därför kan felaktiga resultat returneras.

  • Pågående DML-åtgärder utförs i tabellerna Försäljning och SalesOrders , till exempel följande åtgärder:

    • Du kan göra ändringar i tabellerna när versionen för nästa gång har hämtats med hjälp CHANGE_TRACKING_CURRENT_VERSION()av . Därför kan fler ändringar returneras än förväntat.

    • En transaktion kan checka in under tiden mellan anropet för att hämta ändringar från Sales tabellen och anropet för att hämta ändringar från SalesOrders tabellen. Därför kan resultatet för SalesOrder tabellen ha sekundärnyckelvärde som inte finns i Sales tabellen.

För att lösa de tidigare listade utmaningarna rekommenderar vi att du använder ögonblicksbildisolering. Detta hjälper till att säkerställa konsekvens i ändringsinformationen och undvika konkurrensförhållanden som är relaterade till bakgrundsrensningsuppgiften. Om du inte använder transaktioner med ögonblicksbilder kan det kräva betydligt mer arbete att utveckla ett program som använder ändringsspårning.

Använda ögonblicksbildisolering

Ändringsspårning har utformats för att fungera bra med ögonblicksbildisolering. Isolering av ögonblicksbilder måste vara aktiverat för databasen. Alla steg som krävs för att hämta ändringar måste ingå i en transaktion för ögonblicksbilder. Detta säkerställer att alla ändringar som görs i data vid hämtning av ändringar inte visas för frågorna i ögonblicksbildstransaktionen.

Utför följande steg för att hämta data i en ögonblicksbildtransaktion:

  1. Ange transaktionsisoleringsnivån till ögonblicksbild och starta en transaktion.

  2. Verifiera den senaste synkroniseringsversionen med hjälp CHANGE_TRACKING_MIN_VALID_VERSION()av .

  3. Hämta den version som ska användas nästa gång med hjälp CHANGE_TRACKING_CURRENT_VERSION()av .

  4. Hämta ändringarna för Sales tabellen med hjälp av CHANGETABLE(CHANGES ...)

  5. Hämta ändringarna för SalesOrders tabellen med hjälp av CHANGETABLE(CHANGES ...)

  6. Genomför transaktionen.

Några saker att komma ihåg eftersom alla steg för att hämta ändringar finns i en transaktion för ögonblicksbilder:

  • Om rensningen sker efter att den senaste synkroniseringsversionen har verifierats är resultatet från CHANGETABLE(CHANGES ...) fortfarande giltigt eftersom de borttagningsåtgärder som utförs av rensningen inte visas i transaktionen.

  • Ändringar som görs i Sales tabellen eller SalesOrders tabellen efter att nästa synkroniseringsversion har hämtats visas inte, och anropen till CHANGETABLE(CHANGES ...) returnerar aldrig ändringar med en senare version än den som returneras av CHANGE_TRACKING_CURRENT_VERSION(). Konsekvensen Sales mellan tabellen och SalesOrders tabellen bibehålls också eftersom de transaktioner som checkades in under tiden mellan anropen till CHANGETABLE(CHANGES ...) inte visas.

I följande exempel visas hur ögonblicksbildisolering är aktiverat för en databas.

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

En transaktion för ögonblicksbilder används på följande sätt:

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

Mer information om transaktioner med ögonblicksbilder finns i ANGE TRANSAKTIONSISOLERINGSNIVÅ (Transact-SQL).

Rensning och ögonblicksbildisolering

Om både ögonblicksbildisolering och ändringsspårning aktiveras på samma databas, eller på två olika databaser i samma instans, kan det leda till att rensningsprocessen lämnar utgångna rader i sys.syscommittab när det finns en öppen transaktion i databasen med ögonblicksbildisolering. Detta kan inträffa eftersom rensningsprocessen för ändringsspårning tar hänsyn till ett instansomfattande lågvattenmärke (som är den säkra rensningsversionen) när rensningen utförs. Detta görs för att säkerställa att processen för automatisk rensning av ändringsspårning inte tar bort några rader som kan krävas av den öppna transaktionen i databasen som har ögonblicksbildisolering aktiverat. Håll skrivskyddad ögonblicksbildisolering och transaktioner för ögonblicksbildisolering så korta som möjligt för att säkerställa att utgångna rader rensas sys.syscommittab i tid.

Alternativ till ögonblicksbildisolering

Det finns alternativ till att använda isolering av ögonblicksbilder, men de kräver mer arbete för att se till att alla programkrav uppfylls. Följ dessa steg för att se till att last_synchronization_version är giltig och att data inte tas bort av rensningsprocessen innan ändringarna hämtas:

  1. Kontrollera last_synchronization_version efter anropen till CHANGETABLE().

  2. Kontrollera last_synchronization_version som en del av varje fråga för att hämta ändringar med hjälp CHANGETABLE()av .

Ändringar kan ske efter att synkroniseringsversionen för nästa uppräkning har hämtats. Det finns två sätt att hantera den här situationen. Alternativet som används beror på programmet och hur det kan hantera biverkningarna av varje metod:

  • Ignorera ändringar som har en version som är större än den nya synkroniseringsversionen.

    Den här metoden har sidoeffekten att en ny eller uppdaterad rad skulle hoppas över om den skapades eller uppdaterades före den nya synkroniseringsversionen, men sedan uppdaterades efteråt. Om det finns en ny rad kan ett referensintegritetsproblem uppstå om det fanns en rad i en annan tabell som skapades som refererade till den överhoppade raden. Om det finns en uppdaterad befintlig rad hoppas raden över och synkroniseras inte förrän nästa gång.

  • Inkludera alla ändringar, även de som har en version som är större än den nya synkroniseringsversionen.

    Rader som har en version som är större än den nya synkroniseringsversionen hämtas igen vid nästa synkronisering. Detta måste förväntas och hanteras av programmet.

Förutom de föregående två alternativen kan du utforma en metod som kombinerar båda alternativen, beroende på åtgärden. Du kanske till exempel vill ha ett program där det är bäst att ignorera ändringar som är nyare än nästa synkroniseringsversion där raden skapades eller togs bort, men uppdateringar ignoreras inte.

Anmärkning

Att välja den metod som ska fungera för programmet när du använder ändringsspårning (eller någon anpassad spårningsmekanism) kräver betydande analys. Därför är det mycket enklare att använda isolering av ögonblicksbilder.

Så hanterar ändringsspårning ändringar i en databas

Vissa program som använder ändringsspårning utför dubbelriktad synkronisering med ett annat datalager. Ändringar som görs i SQL Server-databasen uppdateras i det andra datalagret och ändringar som görs i det andra arkivet uppdateras i SQL Server-databasen.

När ett program uppdaterar den lokala databasen med ändringar från ett annat datalager måste programmet utföra följande åtgärder:

  • Sök efter konflikter.

    En konflikt uppstår när samma data ändras samtidigt i båda datalager. Programmet måste kunna söka efter en konflikt och få tillräckligt med information för att konflikten ska kunna lösas.

  • Lagra programkontextinformation.

    Programmet lagrar data som innehåller information om ändringsspårning. Den här informationen skulle vara tillgänglig tillsammans med annan information om ändringsspårning när ändringar hämtades från den lokala databasen. Ett vanligt exempel på den här kontextuella informationen är en identifierare för datalagret som var källan till ändringen.

För att utföra de tidigare åtgärderna kan ett synkroniseringsprogram använda följande funktioner:

  • CHANGETABLE(VERSION...)

    När ett program gör ändringar kan det använda den här funktionen för att söka efter konflikter. Funktionen hämtar den senaste ändringsspårningsinformationen för en angiven rad i en ändringsspårningstabell. Ändringsspårningsinformationen innehåller den version av raden som senast ändrades. Med den här informationen kan ett program avgöra om raden ändrades efter den senaste gången programmet synkroniserades.

  • WITH CHANGE_TRACKING_CONTEXT

    Ett program kan använda den här satsen för att lagra kontextdata.

Sök efter konflikter

I ett tvåvägssynkroniseringsscenario måste klientprogrammet avgöra om en rad inte har uppdaterats sedan programmet senast hämtade ändringarna.

I följande exempel visas hur du använder CHANGETABLE(VERSION ...) funktionen för att söka efter konflikter på det mest effektiva sättet, utan en separat fråga. I exemplet CHANGETABLE(VERSION ...) avgör SYS_CHANGE_VERSION för raden som anges av @product id. CHANGETABLE(CHANGES ...) kan få samma information, men det skulle vara mindre effektivt. Om värdet SYS_CHANGE_VERSION för för raden är större än värdet @last_sync_versionför finns det en konflikt. Om det uppstår en konflikt uppdateras inte raden. Kontrollen ISNULL() krävs eftersom det kanske inte finns någon ändringsinformation tillgänglig för raden. Ingen ändringsinformation skulle finnas om raden inte hade uppdaterats sedan ändringsspårningen aktiverades eller sedan ändringsinformationen rensades.

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

Följande kod kan kontrollera det uppdaterade radantalet och kan identifiera mer information om konflikten.

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

Ange kontextinformation

Med hjälp av WITH CHANGE_TRACKING_CONTEXT -satsen kan ett program lagra kontextinformation tillsammans med ändringsinformationen. Den här informationen kan sedan hämtas från kolumnen SYS_CHANGE_CONTEXT som returneras av CHANGETABLE(CHANGES ...).

Kontextinformation används vanligtvis för att identifiera källan till ändringarna. Om källan till ändringen kan identifieras kan den informationen användas av ett datalager för att undvika att hämta ändringar när den synkroniseras igen.

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

Säkerställa konsekventa och korrekta resultat

Ett program måste överväga rensningsprocessen när det validerar värdet för @last_sync_version. Det beror på att data kunde ha tagits bort efter CHANGE_TRACKING_MIN_VALID_VERSION() att de anropats, men innan uppdateringen gjordes.

Du bör använda ögonblicksbildisolering och göra ändringarna i en transaktion för ögonblicksbilder.

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

Anmärkning

Det finns en möjlighet att raden som uppdateras i ögonblicksbildstransaktionen kan ha uppdaterats i en annan transaktion efter att ögonblicksbildstransaktionen startades. I det här fallet uppstår en konflikt med uppdatering av ögonblicksbildisolering och leder till att transaktionen avslutas. Om detta händer försöker du uppdatera igen. Detta leder sedan till att en ändringsspårningskonflikt identifieras och att inga rader ändras.

Ändringsspårning och dataåterställning

Program som kräver synkronisering måste överväga det fall där en databas med ändringsspårning aktiverat återgår till en tidigare version av data. Detta kan inträffa när en databas har återställts från en säkerhetskopia, när det sker en redundansväxling till en asynkron databasspegling eller när det uppstår ett fel när loggleverans används. Följande scenario illustrerar problemet:

  1. Tabell T1 är ändringsspårad och den lägsta giltiga versionen för tabellen är 50.

  2. Ett klientprogram synkroniserar data vid version 100 och hämtar information om alla ändringar mellan version 50 och 100.

  3. Ytterligare ändringar görs i tabell T1 efter version 100.

  4. Vid version 120 uppstår ett fel och databasadministratören återställer databasen med dataförlust. Efter återställningsåtgärden innehåller tabellen data upp till version 70 och den minsta synkroniserade versionen är fortfarande 50.

    Det innebär att det synkroniserade datalagret har data som inte längre finns i det primära datalagret.

  5. T1 uppdateras många gånger. Det innebär att den aktuella versionen är 130.

  6. Klientprogrammet synkroniseras igen och tillhandahåller en senast synkroniserad version av 100. Klienten validerar det här numret eftersom 100 är större än 50.

    Klienten hämtar ändringar mellan version 100 och 130. I det här läget är klienten inte medveten om att ändringarna mellan 70 och 100 inte är desamma som tidigare. Data på klienten och servern synkroniseras inte.

Om databasen återställdes till en punkt efter version 100 skulle det inte uppstå några problem med synkroniseringen. Klienten och servern synkroniserar data korrekt under nästa synkroniseringsintervall.

Ändringsspårning ger inte stöd för återställning efter dataförlust. Det finns dock två alternativ för att identifiera dessa typer av synkroniseringsproblem:

  • Lagra ett databasversions-ID på servern och uppdatera det här värdet när en databas återställs eller på annat sätt förlorar data. Varje klientprogram lagrar ID:t och varje klient måste verifiera detta ID när data synkroniseras. Om dataförlust inträffar matchar inte ID:t och klienterna initieras igen. En nackdel är att om dataförlusten inte hade överskridit den senaste synkroniserade gränsen kan klienten göra onödiga ominitiering.

  • När en klient frågar efter ändringar registrerar du det senaste synkroniseringsversionsnumret för varje klient på servern. Om det uppstår problem med data matchar inte de senast synkroniserade versionsnumren. Detta indikerar att en återinitiering krävs.