Benachrichtigen, ob und was sich geändert hat.

Hallo,

ich setze PostgreSQL 8.3 mit VS 2008 und NPGSQL ein. Gibt es eine Möglichkeit, dass ich zentral (pro Client) benachrichtigt werde, wenn in einer festgelegten Tabelle Änderungen (durch andere clients) gemacht werden? Außerdem möchte ich auch, dass die gemachten Änderungen in der Nachricht enthalten sind. Kann man sowas mit PostgreSQL? Und wenn ja, wie mach ich sowas?

Gruß

Bubblegum

Siehe Doku zu LISTEN und NOTIFY.


Andreas

In meiner PostgreSQL Dokumentation steht etwas von PQexec nur wo finde ich das?
Unsinn! PQExec ist schon klar. Aber trotzdem verstehe ich die Dokumentation nicht.
Gibt es irgendwo vielleicht ein Beispiel mit C# ind NPGSQL?

Ich meine mich zu erinnern, das in der Dokumentation für npgsql entsprechendes drin stand. Aber das kann ich hier nicht testen, ein Kunde von mir hat das npgsql damals eingesetzt.

        conn = new NpgsqlConnection("Server=127.0.0.1;User id=npgsql_tests;password=npgsql_tests;");
        conn.Open();
    
        NpgsqlCommand command = new NpgsqlCommand("listen notifytest;", conn);
        command.ExecuteNonQuery();
        
        conn.Notification += new NotificationEventHandler(NotificationSupportHelper);
        
        
        command = new NpgsqlCommand("notify notifytest;", _conn);
        command.ExecuteNonQuery();

        Console.ReadLine();  // To prevent program termination before notification is handled.

Habe das genauso gemacht wie es in der Doku steht (siehe oben). Leider wird kein Notify ausgelöst!? Muss man vielleicht noch einen Initialisierungsparameter setzen oder so?

Warum verwendest du einmal “conn” und einmal “_conn”?

Außerdem ist es wohl eleganter, wenn du das NOTIFY einfach in psql absetzt. Dann weißt du, dass das auch durchgeführt wurde. Zumindest zum Testen vereinfacht das die Sache erheblich.

Warum verwendest du einmal “conn” und einmal “_conn”?

“_Conn” erzeuge ich in meiner Applikation nur einmal und nutze die Connections ausschließlich für “listen”. Die “conn’s” sind meine temporären Verbindungen pro Datenbankzugriff. Ich habe jetzt festgestellt, dass sobald ich jedesmal listen aufrufe ich auch das notify event bekomme. Ich bekomme es aber nicht dynamisch, was ja eigentlich der Sinn sein sollte, sondern muss immer listen aufrufen!? Was stimmt da noch nicht?

Hä? Bahnhof.

Also, in deiner Applikation setzt du ein “LISTEN” auf einen bestimmten Begriff, z. B. auf einen Tabellennamen.

Dann schreibst du dir einen AFTER Trigger als FOR EACH STATEMENT, der bei INSERT, UPDATE und DELETE ausgelöst wird. In der dort aufgerufenen Funktion löst du das NOTIFY mit dem Tabellennamen aus. Wenn du pl/pgSQL nimmst, stehen dir die Variablen TG_TABLE_SCHEMA und TG_TABLE_NAME zur Verfügung. Andere Programmiersprachen für serverseitige Funktionen handhaben das ähnlich.

Der Trigger wird bei jeder Operation aufgerufen, die die Tabelle verändert. Dort wird das Notify an deine Applikation gesandt.

voila

Das ist nicht mein Problem, dass Notify Event wird abgesetzt. Auch das Listen greift. Aber nur, wenn ich es immer wieder manuell aufrufe, und gerade das soll doch automatisch gehen. Sonst muss ich ja mit einer Schleife ein Polling machen und genau das will ich ja nicht. Klarer?

Ich habe dein Problem immer noch nicht verstanden.

Wann genau bekommst du das Event zugesandt?

Immer wenn ich manuell listen aufrufe. Dann bekomme ich alle notifies nacheinander.

Genau, so ist das gedacht. Es gibt keinen “Event Listener” der automatisch aufgerufen wird.
Du musst letzendlich in einem Hintergrund-Thread alle x Sekunden das LISTEN aufrufen und dann entsprechend reagieren.

Schau mal in den Archiven der JDBC Mailing Liste. Da hat vor ein paar Wochen jemand eine Helper-Klasse veröffentlicht die den Umgang mit NOTIFY/LISTEN in Java/JDBC vereinfacht (und eben genau diesen Hintegrund-Thread implementiert).

Nachdem Java und C# nicht sooo weit auseinander sind, kannst Du das vielleicht als Grundlage verwenden.

Normalerweise sollte es reichen, vorab einmalig LISTEN aufzurufen, um zukünftig in dieser Verbindung über alle aufgetretenen Signale dieses Namens informiert zu werden.

Der mehrmalige Aufruf von LISTEN ist nicht notwendig.


Allerdings kann es sein, dass z. B. die Signale erst ausgewertet werden, wenn die nächste Aktivität auf der Verbindung zur Datenbank stattfindet. In psql ist das so.

Danke jetzt ist mir einiges klarer. Also ich muss auf jeden Fall mehrmals Listen aufrufen, sonst passiert bei mit gar nichts. Da ich das Ganze für Aktualisierungsprozesse einsetzen möchte, fehlen mir leider Parameter, die ich gerne übergeben möchte. Kennt ihr hierzu irgendwelche Lösungsansätze, um das Problem der fehlenden Parameter zu lösen?

Du musst nicht LISTEN mehrmals aufrufen, es genügt wahrscheinlich, irgendetwas auf dieser Datenbankverbindung zu machen, z. B. ein “SELECT 1;”. Außerdem würde ich mal in die Dokumentation schauen, einige Programmiersprachen können das Event direkt durchreichen, wenn es auftritt. Andere Sprachen und Programme (wie z. B. psql) prüfen so etwas erst nach, wenn wieder etwas passiert). Das Event wird von der Datenbank jedenfalls schon dann auf die Verbindung gelegt, wenn es ausgelöst wird.

Das mit den fehlenden Parametern ist ein heikles Thema. Dazu gibt es derzeit lange Diskussionen auf der -hackers Mailingliste, da eine Neuimplementierung dieses Features ansteht. Dabei soll man dann auch Parameter mitgeben können. Derzeit ist das direkt nicht möglich, man behilft sich, indem man die entsprechenden Daten in eine Tabelle schreibt (das macht dann z. B. der Trigger).