AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Serverseitiges Logbuch über Datenänderungen

Serverseitiges Logbuch über Datenänderungen

Ein Thema von ZOD · begonnen am 20. Okt 2017 · letzter Beitrag vom 26. Okt 2017
Antwort Antwort
ZOD

Registriert seit: 6. Mai 2009
81 Beiträge
 
#1

Serverseitiges Logbuch über Datenänderungen

  Alt 20. Okt 2017, 09:27
Datenbank: Firebird • Version: 2.5 • Zugriff über: SQLExpress
Hallo Zusammen.

Wir denken gerade darüber nach, ob in unserem Umfeld die Integration eines Änderungslogbuchs auf Datenbankserverseite für uns sinnvoll möglich ist.

Hintergrund:
Produktivdatenbank läuft unter Firebird 2.5 (Entwicklungstests zusätzlich mit FB3).
Sämtliche Tabellen haben eindeutige ID-Spalten (über Generatoren erzeugte integer IDs).
Eher unbedeutend in diesem Zusammenhang, aber zur Vollständigkeit:
die Clientanwendung ist unter Delphi entwickelt, DB-Zugriff über DBExpress Komponenten.

Unser gedanklicher Ansatz ist nun folgender:
jede Änderung an einem Datensatz löst den Logbuchprozess aus.
Als Logbuch stellen wir uns eine Tabellenstruktur vor, in der die Änderungen abgelegt werden (Details noch offen).
Im Logbuchprozess soll über Steuertabellen entschieden werden, bei welcher Tabelle in welchem Umfang ein Log geführt wird.
Optimal wäre natürlich z.B. eine stored procedure, die als Parameter den Tabellen-Namen und die Datensatz-ID übergeben bekommt,
so dass mithilfe der Systemtabellen (Metadaten) dann automatisiert Änderungen in der o.g. Logbuchstruktur protokolliert werden - siehe hier Frage 2) unten.

Das ganze ist - gelinde gesagt - noch ein nebulöses Wolkenschloss an Wünschen und Ideen.

Es gibt nun einige Fragen zu diesen Überlegungen, für die ich bei meinen Recherchen (Google und Co) noch keine Antworten gefunden habe - oder ich habe vielleicht ein Verständnisproblem. Hier also die Frageliste:

1) Anstoßen des Logbuchprozesses
Natürlich könnte ich in jeder Tabelle einen Trigger für insert/update/delete anlegen und da den Logbuchprozess anstoßen,
geht das nicht einfacher - sozusagen als zentraler Trigger?

2) Änderungen erkennen
Eine triviale Notwendigkeit ist, dass - um Änderungen zu erkennen - der Zustand vorher mit dem Zustand nacher verglichen werden muss. Prinzipiell ist das mit Tabellen-Trigger vom Typ "before" möglich (old.xx zu new.xx vergleichen).
Gibt es eine Möglichkeit, die beiden Datenmengen (old und new) z.B. einer stored procedure verfügbar zu machen? Dann könnte es vermieden werden, die gesamte Prüflogig in JEDER Tabelle mehrfach abzulegen.

Ich bin dankbar für Tips und Hinweise.
Gruß
Markus
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
644 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#2

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 20. Okt 2017, 09:48
Schaut Euch mal IBexpert an.
Da gibt es so etwas, meine ich schon. Wenn ich mich richtig erinnere werden Trigger und Tabellen in der DB erzeugt die alle Änderungen mitlogen. Wir dort glaube ich für die Replication verwendet. Sollte eigentlich alles erschlagen.
Fritz Westermann
  Mit Zitat antworten Zitat
jobo

Registriert seit: 29. Nov 2010
2.828 Beiträge
 
Delphi 2010 Enterprise
 
#3

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 20. Okt 2017, 09:51
Mir fallen dazu 2,5 Dinge ein:
1. Gerade Firebird handhabt die Updates doch mit neuen Recordversionen. Ich kenne diesen Mechnismus überhaupt nicht, aber es scheint mir naheliegend, sich das vielleicht nutzebar zu machen.. ?
(Einschränkung: Es wäre ein Verfahren, das sehr Produktnahe ist, mit den üblichen Haken.)
2. Gar keine Updates machen, sondern nur inserts und aktive Flag, also quasi eine Highlevel Variante von Firebirds log Mechnismus.
(Einschränkung: Auf Anhieb nicht unbedingt filigran)
2,5. Postgres erlaubt zentrale Trigger, die man prima zum Logging nutzen kann.
Gruß, Jo
  Mit Zitat antworten Zitat
Benutzerbild von joachimd
joachimd

Registriert seit: 17. Feb 2005
Ort: Weitingen
607 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 20. Okt 2017, 10:08
ist http://www.upscene.com/database_audi...and_interbase/ eigentlich noch aktiv? Ist doch genau, was Du willst.
Joachim Dürr
Joachim Dürr Softwareengineering
http://www.jd-engineering.de
  Mit Zitat antworten Zitat
Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
430 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 21. Okt 2017, 16:35
In Firebird gibt es keinen zentralen trigger, glaube ich.
im Trigger der tabelle hast du im Insert/update zugriff auf die NEW-Variable, im Update/delete auf die OLD-variable
technisch kannst du dann deine steuertabelle auslesen und dann entsprechend die old/new variableninhalte vergleichen (beim update).
beim insert würde ich keine feld-log schreiben, weil die werte sind ja eh in der tabelle. beim delete musst halt ma schaun, ob du wegspeichern willst, was gelöscht wurde.

Ich selbst mache es nicht in der datenbank, ich habe mir ein Objekt in Delphi geschrieben, welches beim Dokument erstellen sich eine liste der ausgangswerte im Dataset macht und diese in einer stringliste (hab ich vor Jahren geschrieben, jetzt ginge da vllt auch was anderes, denk da an JSON) und diese liste dann komprimiert in die BD.
Beim Editieren dann wurde die alte Liste wieder geladen und beim erneuten Speichern gegen die alte verglichen und gleiche werte rausgeworfen. Geblieben sind nur die veránderten werte und die wurden wieder komprimiert weggeschrieben.
Das ganze waren dann pro formular und zu überwachender tabelle 3 zeilen, das kann man aber noch optimieren mit einem Wrapper der sich um mehrere tabellen kümmert
  Mit Zitat antworten Zitat
Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
430 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 21. Okt 2017, 16:36
Da fällt mir ein : dadurch dass du ja eine steuertabelle hast, kannst du naturlich dir den trigger code zusammenbauen on-the-fly wenn man die steuertabelle speichert und dann den trigger schreiben, also programmtechnisch schreiben und als script in die DB setzen.

ich habe das mal schnell geschrieben, musst man eventuell anpassen, habe UniDAC und EhLib genutzt und keine Komfort-Sachen reingeschrieben, also alles fest gecoded :

Code:
unit frmMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, DBGridEhGrouping, ToolCtrlsEh,
  DBGridEhToolCtrls, DynVarsEh, EhLibVCL, GridsEh, DBAxisGridsEh, DBGridEh,
  Vcl.StdCtrls, Vcl.ExtCtrls, UniProvider, InterBaseUniProvider, DBAccess, Uni, Data.DB, MemDS;

type
  TForm5 = class(TForm)
    UniConnection1: TUniConnection;
    UniTransaction1: TUniTransaction;
    InterBaseUniProvider1: TInterBaseUniProvider;
    Panel1: TPanel;
    ComboBox1: TComboBox;
    DBGridEh1: TDBGridEh;
    umdTables: TUniMetaData;
    Memo1: TMemo;
    umdCols: TUniMetaData;
    DataSource1: TDataSource;
    procedure FormShow(Sender: TObject);
    procedure UniConnection1AfterConnect(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure DBGridEh1SelectionChanged(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}

procedure TForm5.FormShow(Sender: TObject);
begin
  UniConnection1.Connected := True;
  If UniConnection1.Connected Then begin
    umdTables.Active := True;
    While Not umdTables.Eof Do begin
      ComboBox1.Items.Add(umdTables.FieldByName('TABLE_NAME').AsString);
      umdTables.Next;
    end;
    umdTables.Close;
  end;
  If ComboBox1.Items.Count > 0 Then
    ComboBox1.ItemIndex := 0;
end;

procedure TForm5.UniConnection1AfterConnect(Sender: TObject);
begin
  UniTransaction1.StartTransaction;
end;

procedure TForm5.ComboBox1Change(Sender: TObject);
begin
  umdCols.Close;
  umdCols.Filtered := False;
  umdCols.Filter := 'TABLE_NAME=''' + ComboBox1.Text + '''';
  umdCols.Filtered := True;
  umdCols.Open;
end;

const TRIGGER_START : String = 'SET TERM ^ ; ' + #13#10 + #13#10 +
                               'CREATE OR ALTER TRIGGER TR_LOG_[TABLE_NAME] FOR [TABLE_NAME]' + #13#10 +
                               'ACTIVE AFTER UPDATE POSITION 100' + #13#10 +
                               'AS' + #13#10 +
                               'declare variable LogStr varchar(10000);' + #13#10 +
                               'begin' + #13#10 +
                               ' Logstr = '''';';
      TRIGGER_LOG_LINE : String = ' IF (NEW.DocId <> OLD.DocId) THEN' + #13#10 +
                                  '   Logstr = :LogStr || IIF(:LogStr <> '''', '','', '''') || ''"[FIELD_NAME]":'' || ''"'' || OLD.[FIELD_NAME] || ''"'';';
      TRIGGER_LOG_END : String = ' IF (:LogStr <> '''') THEN' + #13#10 +
                                 ' BEGIN' + #13#10 +
                                 '   LogStr = ''{ "CC": {'' || :LogStr || ''}}'';' + #13#10 +
                                 '   -- INSERT CODE HERE FOR WRITING INTO THE LOGGING TABLE' + #13#10 +
                                 ' end' + #13#10 +
                                 'end^' + #13#10 + #13#10 +
                                 'SET TERM ; ^';

procedure TForm5.DBGridEh1SelectionChanged(Sender: TObject);
var i: Integer;
    sLine : String;
begin
//  sTriggerName := 'TR_LOG_' + ComboBox1.Text; // TODO: delete everything longer than 31 chars
  Memo1.Clear;
  If DBGridEh1.SelectedRows.Count > 0 Then
    Memo1.Lines.Text := TRIGGER_START;
    Memo1.Lines.Text := StringReplace(Memo1.Lines.Text, '[TABLE_NAME]', ComboBox1.Text, [rfReplaceAll, rfIgnoreCase]);
    For i := 0 To DBGridEh1.SelectedRows.Count - 1 Do begin
      umdCols.GotoBookmark(TBookmark(DBGridEh1.SelectedRows.Items[i]));
      sLine := TRIGGER_LOG_LINE;
      sLine := StringReplace(sLine, '[FIELD_NAME]', umdCols.FieldByName('Column_name').AsString, [rfReplaceAll, rfIgnoreCase]);
      Memo1.Lines.Add(sLine);
    end;
    memo1.Lines.Add(TRIGGER_LOG_END)
end;

end.

Was macht der code :

Jedesmal wenn du ein Feld an- oder abwählst in der Tabelle wird der Trigger Code mit der aktuellen Feldliste erstellt, der einen JSON string erstellt mit den alten Werten, wenn was geändert wurde, Damit hast du in der Daten-Tabelle deine aktuelle Version der Daten und mit Zeitstempel rückwärts kannst du zum Ursprung zurückkehren.

man kann noch einen Delete trigger machen mit allen Feldern, wenn man will, damit man auch bei gelöschten Registern noch Daten hat

https://puu.sh/y3FJg/e1f21a30f9.png

Geändert von MyRealName (21. Okt 2017 um 19:10 Uhr) Grund: Code/Screenshot hinzugefügt
  Mit Zitat antworten Zitat
tsteinmaurer

Registriert seit: 8. Sep 2008
Ort: Linz, Österreich
527 Beiträge
 
#7

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 22. Okt 2017, 16:37
Hallo Joachim,
Zitat:
Natürlich.
  Mit Zitat antworten Zitat
ZOD

Registriert seit: 6. Mai 2009
81 Beiträge
 
#8

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 23. Okt 2017, 06:32
Guten Morgen,

vielen Dank für die Tipps und Vorschläge. Ich schaue mir das an und werde mich
hier zurückmelden - sozusagen als Fortschrittsbalken .
  Mit Zitat antworten Zitat
mquadrat

Registriert seit: 13. Feb 2004
1.113 Beiträge
 
Delphi XE2 Professional
 
#9

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 23. Okt 2017, 07:23
Wir haben bei unseren Desktop-Anwendungen die Variante mit den Triggern je Tabelle. Ist bei uns Grundlage für einen Replizierungslayer. Bei den Web-Anwendungen sitzt die Logik in der Datenzugriffsschicht.
  Mit Zitat antworten Zitat
ZOD

Registriert seit: 6. Mai 2009
81 Beiträge
 
#10

AW: Serverseitiges Logbuch über Datenänderungen

  Alt 26. Okt 2017, 14:40
Hier die versprochene Rückmeldung:

wir setzen zur DB Wartung IBExpert ein. Hier gibt es einen Log-Manager.
Ich hatte wohl Tomaten auf den Auge, dass ich das bei meiner Suche nicht gesehen habe.

Wir haben das nun scharf geschaltet (es werden im IBExpert entsprechende Tabellen und Trigger erzeugt) und werden mit den hier entstehenden Daten die Darstellung der Änderungen in unserer Applikation gestalten.

Nochmals danke für alle Beiträge - insbesondere an MyRealName und Fritzew
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:33 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2020 by Daniel R. Wolf