Używanie serwera bazy danych H2 do powiadamiania o zmianach klientów (przesyłanie wiadomości JMS)
Z powodzeniem używam bazy danych H2 w trybie AUTO_SERVER, aby plik bazy danych był współużytkowany przez wielu klientów komputerów stacjonarnych w sieci w sposób przezroczysty. W ten sposób serwer jest wybierany wśród klientów i wszystkich innych klientów odczytywanych z serwera tcp.
Brakuje mi sposobu, w jaki klient lub serwer może powiadomić wszystkie inne komputery klienckie o czymś, co zostało zmienione w bazie danych. Obecnie używam kanału JGroups, aby umożliwić wszystkim klientom komunikowanie się ze sobą, ale jest to kolejny punkt awarii i inny algorytm wyboru lidera, który działa równolegle z H2.
Czy nie ma innej metody? Przeczytałem o JMS (Java Message Service Java API), który jest obsługiwany w niektórych bazach danych. Jakaś podpowiedź do H2?
Dzięki
EDYTOWAĆ:
Poniższy kod jest adaptacją bieżącej odpowiedzi, jeśli uruchomię najpierw Sender (ustaw args jako „nadawca”), łączy się on jako serwer z bazą danych H2, a następnie wykonuję Receiver (ustaw args jako „odbiornik”) na zdalnych komputerach i łączą się jako klienci.
Jednak tylko serwer otrzymuje powiadomienia, klienci nic nie otrzymują.
Ma to sens z tego, co obecnie wiem: wyzwalacz jest wywoływany tylko na serwerze, funkcja klienta zdefiniowana z klienta lub serwera jest wywoływana na kliencie lub serwerze, ale nie na wszystkich klientach (i serwerze) połączonych z bazą danych.
Czy istnieje sposób na dostosowanie poniższego, aby powiadomić wszystkie połączone instancje o zmianie bazy danych?
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();
}
}
}
}