我在AUTO_SERVER模式下成功使用H2数据库,以便透明地在网络上的多个桌面客户端之间共享数据库文件。 这样,在客户端中选择服务器,从tcp服务器读取所有其他客户端。
我缺少的是客户端或服务器如何通知所有其他桌面客户端数据库中已更改的内容。 现在我正在使用JGroups通道让所有客户端相互通信,但这是另一个故障点,另一个领导者选举算法与H2并行运行。
没有其他方法吗? 我已经阅读了一些数据库支持的JMS(Java消息服务Java API)。 H2的任何提示?
由于
编辑:
以下代码是当前答案的改编,如果我首先启动Sender(将args设置为“sender”),他将服务器连接到H2数据库,然后执行Receiver(将args设置为“receiver”)远程机器,它们作为客户端连接。
然而,只有服务器收到通知,客户端才收到任何通知。
根据我目前所知,这是有道理的:只在服务器上调用触发器,在客户端或服务器上调用从客户端或服务器调用的用户定义函数,而不是在连接到客户端或服务器的所有客户端(和服务器)上调用。数据库中。
那么有没有办法调整以下内容来通知所有连接的实例数据库中的更改?
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();
}
}
}
}
答案 0 :(得分:1)
H2没有实现JMS(事实上我不知道有哪个数据库)。但是,您可以使用触发器和用户定义的函数在H2中构建一个简单的通知机制,如下所示。请注意,这将需要H2中的多线程模式,该模式尚未完全测试。因此,使用单独的数据库进行消息传递可能比用于数据的数据库更有意义。
import java.sql.*;
import java.util.concurrent.atomic.AtomicLong;
import org.h2.tools.TriggerAdapter;
public class TestSimpleDb {
public static void main(String[] args) throws Exception {
final String url = "jdbc:h2:mem:test;multi_threaded=true";
Connection conn = DriverManager.getConnection(url);
Statement stat = conn.createStatement();
stat.execute("create alias wait_for_change for \"" +
TestSimpleDb.class.getName() +
".waitForChange\"");
stat.execute("create table test(id identity)");
stat.execute("create trigger notifier " +
"before insert, update, delete, rollback " +
"on test call \"" +
TestSimpleDb.Notifier.class.getName() + "\"");
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(10000)");
System.out.println("Receiver: event received");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Thread.sleep(500);
for (int i = 0; i < 10; i++) {
System.out.println("Sender: I change something...");
stat.execute("insert into test values(null)");
Thread.sleep(1000);
}
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();
}
}
}
}