Einfache Replikation von Stammdaten

In diesem BLOG geht es darum, wie man mit wenig Aufwand eine einfache Replikation für Stammdaten aufsetzen kann.

Im vorliegenden Beispiel geht es um Adressen, die regelmäßig aus der Datenbank einer ERP-Software gelesen und dann in einer weiteren Instanz der gleichen ERP-Software bereit gestellt werden sollen. Beide Datenbankeninstanzen verwenden die gleichen Datenstrukturen.

Unser Ziel ist es, Daten regelmäßig zwischen den Datenbankinstanzen ohne manuellen Eingriff zu replizieren. Die Übertragung soll direkt zwischen den Datenbanken erfolgen, auf Dateiformate wie XML oder CSV, kann daher verzichtet werden.

Der ausführende Prozess soll so implementiert werden, dass dieser automatisch und dialoglos ablaufen kann und zusätzlich auf Ausnahmen angemessen reagiert.

Was ist Replikation und warum sollte man Daten replizieren?

Bei einer Datenreplikation wird eine konsistente Kopie der Daten zur weiteren Nutzung angefertigt und in anderen IT-Systemen bereitgestellt. Durch die Replikation können Einsparungen bei der Pflege der Daten erreicht werden, außerdem können Divergenzen zwischen Datenständen reduziert oder eliminiert werden.

Fiktive Aufgabenstellung

Nachfolgend ist beschrieben, unter welchen Bedingungen Adressen repliziert werden sollen:

  • Neue Adressen müssen in die gleichnamige Tabelle der zweiten Datenbankinstanz übernommen werden
  • Änderungen an bestehenden Adressen müssen in die gleichnamige Tabelle der zweiten Datenbankinstanz übertragen werden
  • Löschen wird durch eine Kennzeichnung in den Daten abgefangen. Das Kennzeichen befindet sich direkt in der Tabelle, wird demnach also wie eine Änderung behandelt
  • Aus Performancegründen sollen natürlich nicht jedes Mal alle Datensätze einer Tabelle komplett in die Zielinstanz übertragen werden, sondern nur neue Sätze und Änderungen

Hintergrund

Nun folgen technische Details, sozusagen als Hintergrund:

  • Die Datenbank ist ein ADVANTAGE DATABASE SERVER (abgekürzt auch ADS)
  • Der ADS unterstützt verschiedene Betriebsmodi und besitzt eigentlich auch eine Erweiterung  für die Replikation von Daten. Voraussetzung für die Nutzbarkeit der Replikationsoption ist jedoch ein Betriebsmodus, der Tabellen in ein so genanntes Dictionary einbindet. Steht dieser Modus nicht zur Verfügung, steht die datenbankeigene Replikation nicht zur Verfügung
  • Die ERP nutzt das Dictionary erwartungsgemäß nicht, sonst hätte ich diesen Text hier ja auch nicht schreiben müssen.
  • Im vorliegenden Betriebsmodus können Tabellen allerdings einen AUTOINC Datentyp implementieren sowie den Datentyp ROWVERSION.
  • Im ersten Fall werden neue Sätze mit einem inkrementierten Zähler belegt, der eindeutig ist.
  • ROWVERSION inkrementiert hingegen einen Zähler im Tabellenheader, der für jedes INSERT oder UPDATE auf einem beliebigen Datensatz inkrementiert wird.
  • Der Unterschied ist also, dass ein Datensatz nur einmal einen AUTOINC Wert bekommt, ROWVERSION kann sich jedoch immer ändern. Beide Werte sind hingegen in ihrem Zählkreis eindeutig.

Ich habe im Projekt das Feld _ID als AUTOINC-Feld und das Feld _VERSION als Feld für die ROWVERSION in den benötigten Tabellen identifiziert. Im Weiteren Text werde ich einfach diese beiden Feldnamen verwenden.

Konzept

Zunächst musste ich mir überlegen, wir ich herausfinden kann, wie ich neue und geänderte Daten identifiziere. Konnte ich die auch noch gleich behandeln, dann wäre alles einfacher?!

Natürlich kann ich nun einfach das Feld _VERSION mit dem Datentyp ROWVERSION nutzen, der für einen Datensatz einen anderen Wert annimmt, wenn dieser sich geändert hat. Und glücklicherweise bekommt auch jeder neue Datensatz immer einen entsprechenden Wert zugewiesen.

Ich konnte mich also darauf verlassen, dass in allen Datensätzen im Feld _VERSION immer ein eindeutiger Zähler vorhanden war, und jeder Datensatz in _ID einen eindeutigen Schlüssel besaß.

Nun wurde mein Replikationsszenario überschaubar:

  • Bei der der allerersten Übertragung konnte ich alle Datensätze nehmen
  • Im Zusammenhang mit einem Replikationslauf muss ich mir zum Schluss den höchsten Wert von _VERSION merken
  • Wenn ich im nächsten Replikationslauf nur Daten selektiere, bei denen :VERSION größer ist als der gemerkte Wert sind, habe ich automatisch alle neuen und geänderten Daten.

Verprobung

Um sicher zu stellen, dass sich alles verhält wie gedacht, habe ich zur Verprobung manuelle Änderungen an einigen Datensätzen vorgenommen. Nachfolgend dazu das Beispiel.

Ausgangssituation ist Kundennummer 1002. Hier wird der Name geändert.

1

Ich mache für den Kunden die Korrektur, da in meinem Beispiel der Name nicht voll ausgeschrieben ist.

Neuer Datenstand ist nun folgender:

2

Deutlich zu erkennen ist, dass die Datenbank nach der Änderung von „Hans Medizin…“ nach „Hans Meyer Medizin…“ den Wert in der Spalte _VERSION um 1 erhöht hat.

Wenn vor dieser Änderung bereits eine Replikation von Daten stattgefunden hat, so ist es über eine SQL-Abfrage sehr einfach möglich, neue und geänderte Datensätze zu finden, da diese in _VERSION den zuletzt gemerkten Wert überschreiten:

SELECT * FROM kundena WHERE _version >= 15

3

Durch meinen Test (den ich hier nur abgekürzt darstelle) habe ich also sicher gestellt, dass ich neue und geänderte Datensätze finden kann, wenn ich einen einfachen Vergleichswert habe; dieser besteht für eine Tabelle nur aus einer einfachen Zahl. Habe ich den Wert anfänglich nicht, kann ich 0 verwenden, um dann zur Initialisierung einfach alle Sätze zu selektieren.

In nachfolgenden Übertragungs-Szenarien muss also nur dafür gesorgt werden, dass nach der Übertragung von Daten in ein Filial-System der relevante Vergleichswert gespeichert wird, um für spätere Übertragungen diesen Anhaltspunkt zu haben. In allen folgenden SWQL.-Codes wird dazu Bezug auf die Tabelle _REPMASTER genommen, die jeweils einen Steuer-Datensatz für jede zu replizierende Tabelle enthält.

Der Aufbau wie folgt (Ur-Zustand):

4

Der Aufbau nach Inbetriebnahme (siehe Feld VERSION):

5

Nach jedem Durchlauf der Replikationsprozesse, werden also im Feld VERSION für jede Tabelle die Datenstände gemerkt. Somit können einfach und schnell alle neuen und geänderten Datensätze für den nächsten Replikationsdurchgang ermittelt werden.

  1. Sicherstellung der Übertragung aller Änderungen

    Die Sicherstellung, das immer alle geänderten Daten komplett Übertragen werden, ist durch das Transaktionssystem der Datenbank geregelt. Aus diesem Grund darf die Anwendung nur im Modus REMOTE laufen.

  2. Erweiterung der Replikation

    Die Hinzunahme weiterer Tabellen ist einfach. Die Tabelle ist unter _REPMASTER einzutragen und mit der Sortierung zu versehen. Die Sortierung / Gruppierung dient lediglich der Unterscheidung verschiedener Datenkreise, kann jedoch auch verwendet werden, um eine bestimmte Abarbeitungsreihenfolge zu erzwingen.

    Das Feld AKTIV wird auf TRUE gesetzt, s.d. die Datenbank am Prozess teilnimmt. Zusätzlich ist im UC ein Übertragungs-SQL anzulegen. Alle anderen Mechanismen werden generisch gesteuert.

  3. Anpassung der Datenbankstrukturen bei betroffenen Tabellen

    Sofern nicht vorhanden, sind folgende Felder in der QUELL-Datenbank anzulegen
    1) _ID Typ AUTOINC
    2) _VERSION Typ ROWVERSION

  4. Sofern nicht vorhanden, sind folgende Felder in den ZIEL-Datenbanken anzulegen:
    1) _ID Typ INTEGER
    2) _VERSION Typ INTEGER

    ACHTUNG: AUTOINC darf in den ZIEL-Datenbanken als Typ hier in diesem Beispiel nicht verwendet werden!

    Sofern ein automatisches Update-Programm die Datentypen verändert, sind diese nach dem Update anzupassen. Die Feldnamen sind nur beispielhaft und können frei gewählt werden. Es empfiehlt sich jedoch, die Benennung deutlich von der Benennung der „normalen“ Datenbankfelder abzugrenzen, beispielsweise durch den Unterstrich. Werden andere Feldnamen verwendet, sind zudem die SQL-Scripte und die _REP* Tabellen anzupassen, die die Steuerung der Replikation übernehmen.

Neue Tabellen einbinden

  • Abschalten der UC-Prozesse
  • Eintragen der Tabelle in _REPMASTER auf der Quelldatenbank
  • Vergeben einer Ordnungsgruppe
  • Vorgabewert „Version = 0“ sollte gesetzt sein
  • Einfügen des Übertragungsskripts in den UC (mit den Echtnamen)
  • Setzen des Schalters AKTIV (definitiv zuletzt)!
  • Einschalten der UC-Prozesse

Durchführung von Datenbank-Updates

  • Abschalten der UC-Prozesse
  • Durchführung zuerst auf der Quelldatenbank (empfohlen)
  • Durchführung weiterer Update auf den Replikationszielen (auf Quelle kann schon wieder gearbeitet werden)
  • Durchführung der Prozedur REP_INIT
  • Einschalten der UC-Prozesse

Kompletten Bestandsabgleich für alle Tabellen erzwingen (REP_INIT)

  • Abschalten der UC-Prozesse
  • SQL auf _REPMASTER in Quelle: UPDATE _repmaster SET version = 0;
  • Einschalten der UC-Prozesse

Diese Prozedur kann nachts vom UC erzwungen werden, während der normale Replikationsprozess nicht läuft. REP_INIT ist jedoch normalerweise nicht nötig und behindert andere nächtliche Prozesse!

Im Zusammenhang mit dem Projekt ergeben sich unter anderem folgende Fragen:

  • Wie kann ich feststellen, ob im Quellsystem Daten neu eingefügt oder geändert wurden und damit neu repliziert werden müssen?
  • Wie kann ich die Datenbankdaten so replizieren, dass diese in der Zielinstanz vollständig und in gewünschter Form ankommen?
  • Kann  ich manuelle Nachbearbeitung verhindern oder im Falle eines Falles automatisieren?