Verwenden des H2-Datenbankservers zum Benachrichtigen von Clients über Änderungen (JMS-Nachrichtenübermittlung)

Ich verwende die H2-Datenbank erfolgreich im AUTO_SERVER-Modus, sodass eine Datenbankdatei für mehrere Desktop-Clients in einem Netzwerk transparent freigegeben wird. Auf diese Weise wird ein Server unter den Clients ausgewählt und alle anderen Clients lesen vom TCP-Server.

Was mir fehlt, ist, wie ein Client oder der Server allen anderen Desktop-Clients mitteilen kann, dass etwas in der Datenbank geändert wurde. Im Moment benutze ich einen JGroups-Kanal, um alle Kunden miteinander kommunizieren zu lassen. Dies ist jedoch ein weiterer Fehlerpunkt und ein weiterer Algorithmus zur Wahl von Führungskräften, der parallel zu H2 ausgeführt wird.

Gibt es keine andere Methode? Ich habe über das JMS (Java Message Service Java API) gelesen, das in einigen Datenbanken unterstützt wird. Irgendein Hinweis für H2?

Vielen Dank

BEARBEITEN:

Der folgende Code ist eine Anpassung der aktuellen Antwort. Wenn ich zuerst den Absender starte (setze Args als "Absender"), verbindet er sich als Server mit der H2-Datenbank, dann führe ich Receiver (setze Args als "Empfänger") auf entfernten Rechnern aus und Sie verbinden sich als Clients.

Nur der Server erhält Benachrichtigungen, die Clients erhalten nichts.

Dies ist nach meinem derzeitigen Kenntnisstand sinnvoll: Ein Trigger wird nur auf dem Server aufgerufen, eine benutzerdefinierte Funktion, die von einem Client oder Server aufgerufen wird, wird auf dem Client oder Server aufgerufen, jedoch nicht auf allen mit der Datenbank verbundenen Clients (und Servern).

Gibt es eine Möglichkeit, das Folgende anzupassen, um alle verbundenen Instanzen über eine Änderung in der Datenbank zu benachrichtigen?

import java.io.File;
import java.sql.*;
import java.util.concurrent.atomic.AtomicLong;
import org.h2.tools.TriggerAdapter;

public class TestSimpleDB2
{

    public static void main(String[] args) throws Exception
    {
        //final String url = "jdbc:h2:mem:test;multi_threaded=true";
        final String url = "jdbc:h2:" + File.separator + "mnt/testdir/PlanIGS" + File.separator
                + "persondb;create=true;AUTO_SERVER=TRUE;multi_threaded=true";
        Connection conn = DriverManager.getConnection(url);
        Statement stat = conn.createStatement();

        boolean isSender = false;
        args = new String[]
        {
            "sender"
        };
        for (String arg : args)
        {
            if (arg.contains("receiver"))
            {
                System.out.println("receiver starting");
                isSender = false;
            }
            else if (arg.contains("sender"))
            {
                System.out.println("sender starting");
                isSender = true;
            }
        }

        if (isSender)
        {
            stat.execute("create alias wait_for_change for \""
                    + TestSimpleDB2.class.getName()
                    + ".waitForChange\"");
            stat.execute("create table test(id identity)");
            stat.execute("create trigger notifier "
                    + "before insert, update, delete, rollback "
                    + "on test call \""
                    + TestSimpleDB2.Notifier.class.getName() + "\"");

            Thread.sleep(1000);
            for (int i = 0; i < 10; i++)
            {
                System.out.println("Sender: I change something...");
                stat.execute("insert into test values(null)");
                Thread.sleep(2000);
            }
        }
        else
        {
            new Thread()
            {
                public void run()
                {
                    try
                    {
                        Connection conn = DriverManager.getConnection(url);
                        for (int i = 0; i < 10; i++)
                        {
                            conn.createStatement().execute(
                                    "call wait_for_change(100000)");
                            System.out.println("Receiver: event received");
                        }
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
        conn.close();
    }

    static AtomicLong modCount = new AtomicLong();

    public static void waitForChange(long maxWaitMillis)
    {
        synchronized (modCount)
        {
            try
            {
                modCount.wait(maxWaitMillis);
            }
            catch (InterruptedException e)
            {
                // ignore
            }
        }
    }

    public static class Notifier extends TriggerAdapter
    {

        public void fire(Connection conn, ResultSet oldRow, ResultSet newRow)
                throws SQLException
        {
            modCount.incrementAndGet();
            synchronized (modCount)
            {
                modCount.notifyAll();
            }
        }
    }
}

Antworten auf die Frage(1)

Ihre Antwort auf die Frage