Hallo!
Vorab, ich habe versucht das so zu entwickeln, das man es in bestehende Systeme einbinden kann, ohne in Abfragen eingreifen zu müssen. Und ich denke ich bin auf dem richtigen Weg das das auch gelingen sollte.
Um das Gehampel mit zwei ID-Feldern zu vermeiden, könntest du auch ein ID-Feld und ein Herkunftsfeld definieren. Das Herkunftsfeld definiert, welche dezentrale Datenbank zur Eingabe verwendet wurde. Wenn der Datensatz zur zentralen Datenbank hochgeladen wird, wird das Herkunftsfeld geändert und eine neue ID vergeben. Die Änderung wird dann zurückgesendet, bzw. generell komplett verteilt.
Wobei ich mich frage, was das bringen soll, wenn die Id's und das Herkunftsfeld geändert wird. Es geht doch einzig und allein darum, daß ein Datensatz eindeutig identifiziert werden kann, wobei verschiedene, ich nehm jetzt mal ein altmodisches Wort dafür, 'Nummerngeneratoren' für die ID verwendet werden. Und zwar für jede Datenbank ein eigener, wobei das Herkunftsfeld festlegt, welche Datenbank das jetzt war.
Ja, aber da bekome ich mit meinem obigen Vorhaben probleme, ich müsste sämtliche Abfragen, Links, Parameter... verändern, da ich keien eindeutige ID mehr habe. Wenn aber alle Datensätze überall eindeutig über eine Id definiert sind, wird das erheblich einfacher, und wenn dann noch die Tabellen komplett gleich sind, dann befindet man sich im 7. Synchronistaions-Himmel, wobei ich weiß das man das eigentlich von eienr anderen Seite her angehen sollte, aber ich weiß schon was ich tue wenn ich das für eine Anwendung implementiere.
So, und nun wieder zum eigentlichen Problem.
Ich habe vor kurzem noch an einem Synchronisationsproblem gearbeitet, dessen Lösung wir irgendwan vor einem Jahr oder so diskutiert haben. Im Archiv wirst Du sicherlich noch fündig. Dabei haeb ich jedoch für jeden Datensatz in den dezentralen Datenbanken zwei ID's gepflegt, eine lokale ID und eine Server-ID. Ein Grund dafür war eigentlich,daß die dezentralen Datenbanken viel weniger Daten speichern mußten, da sie nur für das Remotesystem relevante Daten vom Server bekamen. Aber das ist eine andere Geschichte.
Egal, nehmen wir einmal an, wir verwenden ID + Herkunft für die Identifikation.
Ich verwende zwei Methoden, um geänderte Daten festzustellen. Am zentralen Server wird die Timestamp verwendet, und die Remotedatenbanken verwenden ein Änderungsflag.
Gut, das heißt Du hast verschieden Tabellen auf dem Client und dem Master, oder zumindest entsprechende verschiedene Abfragen in der Anwendung, oder? Das will ich nicht!
Der Grund dafür ist, daß ich mich nicht mit den wahrscheinlcih sicherlich vorhandenen Unterschieden der Systemzeiten auseinandersetzen will.
Wieso? Das ist doch das einfachste! Du loggst auf beiden Systemen nicht eine Zeit sondern die jeweils eigene System-Zeit und ziehst die dann bei Vergleichen heran!
So, wie läuft nun _meine_ Synchronisation ab:
1.) Grundsätzlich startet nur das Remotesystem die Synchronisation.
bei mir auch
2.) Hier werden zuerst alle Datensätze der zu synchronisierenden Tabellen ermittelt, wobei unerheblich ist, ob es neue oder modifizierte Datensätze sind.
genauso bei mir
3.) diese Daten werden in ein neutrales Format (Text-Dateien) gebracht und an den Server übertragen.
vielleicht nicht neutral, aber SQL-Statements finde ich besser
4.) Als Meta-Information wird noch die Remotehost-ID und der Zeitpunkt der letzten Synchronisation übertragen.
der Remote-Host wird auch übertragen, der letzte Sync Timestamp wird aber aus der jeweils eigenen speziellen sync-Tabelle ausgelesen, dem client entsprechend
5.) Am Server wird zuerst einmal der aktuelle Timestamp ermittelt. Dieser Wert dient einerseits dazu, daß nur Daten, die bis zu diesem Wert in der Datenbank sind berücksichtigt werden, zum anderen wird er auch zurück an das Remotesystem übertragen, wo für die nächste Synchronisation als 'letzter Synchronisationszeitpunkt' abgelegt wird.
ich muß gestehen, das meine Timestamps nicht immer 100% gleich sind, sollt eich vielleicht mal drüber nachdenken.
6.) dann wird jeder übertragene Datensatz des Remotesyystems eingepflegt. Das passiert so, daß zuerst anhand der ID (+Herkunftskennung) geprüft wird, ob er schon vrhanden ist. Wenn nicht, dann wird ein Insert geamcht, ansonst ein Update. Für die Bestätigung werden nun für jeden Datensatz eine Rückmeldung generiert, die praktisch dem Übertragungs-Datensatzformat entspricht.
Das wird bei mir halt schon auf dem Client system ermittelt und entsprechend vorher generiert und dann auf dem Master ausgeführt.
7.) Ist das erledigt, werden am Server nun alle Datensätze ausgelesen, die zwischen dem letzten Synchronisationstzeitpunkt (das ist der vom Remotesystem übertragene Zeitpunkt) und dem unter 5.) ermittelten Timestamp geändert wurden. Diese Daten werde auch in das Übertragungs-Text-Format übergeführt.
Das habe ich auch so vor, halt mit der unterscheidung ob Update oder Insert, anhand einer StatusID, odr Flag oder wie auch immer Du das nennst, und der HerkuunftsID und dem Timestamp. Aus den Daten kann ich schon vor der Übertragung ermittlen, was für ein Statement ich generieren muß.
8.) die so gesammelten Daten werden nun an das Remotesystem, gemeinsam mit dem unter 5.) ermittelten Timestamps übertragen.
9.) Am Remotesystem wird nun analog zum Server die Daten Satz für Satz in die Datenbank eingepflegt. Dabei wird wieder überprüft, ob es den Datensatz schon gibt und entsprechend ein Insert oder Updatestatement generiert.
10.) der Timestamp wird am Remotesystem lkal abgelegt, um bei der nächsten Synchronisation wiederverwendet zu werden.
Einige Anmerkungen zum Übertragungsformat. Ich habe, da mir am Remotesystem kein XML-Parser zur Verfügung steht, und weil bei der mir zur Verfügung stehenden Übertragungsgeschwindigkeit XML etwas zu viel Overhead hat ein einfaches TextFormat gewählt. Eine solche Übertragungsdatei siehtvielleicht so aus:
[TABELLENNAME]
ID:4711
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
ID:4712
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
...
Warum hast Du kein CSV-Format gewählt?
Also ich mache das ganz anders, ich generiere auf dem Remote-Syestem Insert- und Update-Statements, die ich urlencode und mit curl an den Master schicke, dann mit PHP an die Standardeingabe für das mysql-Kommandozeilen-Tool übergebe. Das funktioniert sehr gut und ist darüberhinaus sehr schnell, wobei das Nadelöhr bei mir eher in der Übertragungszeit(trotz DSL) liegt, ich habe mit 120KB Daten gestestet, das dauert schon 10 Sekunden, vom Starten von Curl bis zur Erfolgsmeldung das die Daten am Server angekommen sind, sonst mache ich nichts!
Was mir noch gar nicht gut gefällt, ich schreibe die Inserts ohne ID in die Master-Datenbank, damit die hier "globale" ID bekommen. Um diese ID wieder zurückzuermitteln, mache ich das zur Zeit so, das ich die Datensätze (alle die neuer sind als der Startzeitpunkt der Synchronisation)komplett mit mysqldump auslese und wieder zurückübertrage, also extremst viel overhead, das sollte ich vielleicht mal ändern.
Mit dem Feld MODFLAG in der Antwort kann ich steuern, was lokal passieren soll. Wenn MODFLAG z.B. Null ist, dann ist alles gut gegangen, ich kann lokal bei diesem Datensatz das Flag auch zurücksetzen. Wenn es nicht Null ist, dann enthält es einen vereinbarten Fehlercode, auf dem halt irgenwie reagiert werden sollte. Der Datensatz muß in jedem Fall bei der nächsten Synchronisation wieder übertragen werden. Auch bei einem Konfliktmanagment können diese Rückmeldungen wertvoll sein.
Das Erzeigen und Verarbeiten läßt sich mit einem einfachen Zustandsautomaten lösen und ist eigentlich beliebig ausbaubar.
Sowas brauche ich auch noch, aber erstmal soll die Synchronisation so funktionieren, mal gucken wie ich das am besten integrieren kann.
So ich hoffe, das so halbwegs auf die Reihe gebracht zu haben, ohne vollkommen unverständlich zu sein. Aber wenn Du noch Fragen hast, weißt Du ja, wo Du mich findest;-)
Vielen Dank! Ich habe zur Zeit einen einfachen Synchronisationsmechanismus laufen, der seeehr einfach ist, aber leider etwas unsicher, denn er benötigt einen offenen mySQL-Port und wird unverschlüsselt quer durch das Internet geleitet. Die Variante über http(s) ist doch "etwas" komplizierter als ich es zu hoffen gewagt hatte! Aber das hätte ich schon locker geschafft, das was die ganze Sache wirklich kompliziert macht ist die von mir angestrebte "Modularität", also das ich diesen Mechansismus sehr leicht über andere Anwendungen drüberegen kann, egal was für Tabellen, egal was für Spaltennamen...
Jedenfalls vielen Dank für Deine Hilfe!
Viele Grüße
Andreas