H2 トリガー機能を使用して、自動混合モード (AUTO_SERVER=TRUE) で H2 データベースに接続されているクライアントが、データベース テーブルで何かが変更されたときに通知を受信できるようにしようとしています。
test(id INTEGER NOT NULL AUTO_INCREMENT, message varchar(1024))
これまでのところ、H2 サーバーのみが TRIGGER 通知を受信しますが、クライアントは通知を受信できないため、データベースへの変更を確認する唯一の方法は、テーブルへのクエリでポーリングすることですが、この方法では TRIGGER 自体は役に立ちません。すべてのクライアントとサーバーはデータベースに変更がないかポーリングします!
トリガーが接続されているすべてのクライアントに通知するか、各クライアント内のメソッドを呼び出して、挿入によってテーブルが変更されたことを認識させる方法はありますか (削除または更新のケースは気にしません)。
Thomas Mueller (H2 データベース作成者) によるこの回答に基づいたコードを以下に投稿します。
import java.sql.*;
import java.util.concurrent.atomic.AtomicLong;
import org.h2.api.Trigger;
public class TestSimpleDb
{
public static void main(String[] args) throws Exception
{
final String url = "jdbc:h2:test;create=true;AUTO_SERVER=TRUE;multi_threaded=true";
boolean isSender = false;
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)
{
Connection conn = DriverManager.getConnection(url);
Statement stat = conn.createStatement();
stat.execute("create table test(id INTEGER NOT NULL AUTO_INCREMENT, message varchar(1024))");
stat.execute("create trigger notifier "
+ "before insert, update, delete, rollback "
+ "on test FOR EACH ROW call \""
+ TestSimpleDb.Notifier.class.getName() + "\"");
Thread.sleep(500);
for (int i = 0; i < 10; i++) {
System.out.println("Sender: I change something...");
stat.execute("insert into test(message) values('my message')");
Thread.sleep(1000);
}
conn.close();
}
else
{
new Thread() {
public void run() {
try {
Connection conn = DriverManager.getConnection(url);
while (true) {
;
//this loop is just to keep the thread alive..
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}.start();
}
}
public static class Notifier implements Trigger
{
@Override
public void init(Connection cnctn, String string, String string1, String string2, boolean bln, int i) throws SQLException {
// Initializing trigger
}
@Override
public void fire(Connection conn, Object[] oldRow, Object[] newRow) throws SQLException {
if (newRow != null) {
System.out.println("Received: " + (String) newRow[1]);
}
}
@Override
public void close() {
// ignore
}
@Override
public void remove() {
// ignore
}
}
}