H2触发器,未在远程客户端上以自动混合模式(AUTO_SERVER = TRUE)调用通知程序

时间:2013-10-11 13:14:00

标签: java h2

我正在尝试使用H2 Trigger工具让自动混合模式下连接到H2数据库的客户端(AUTO_SERVER = TRUE)在数据库表中发生更改时收到通知

test(id INTEGER NOT NULL AUTO_INCREMENT, message varchar(1024))

到目前为止只有H2服务器接收到TRIGGER通知,而客户端无法接收任何通知,因此检查数据库更改的唯一方法是查询表中的查询,但这样TRIGGER本身就没用了,我可以只是简单地所有客户端和服务器轮询数据库以进行更改!。

是否有某种方法让触发器通知所有连接的客户端或调用每个客户端内的方法,以便他们意识到表已经通过插入进行了修改(不打扰删除或更新案例)?

我发布了下面的代码,该代码基于Thomas Mueller(H2数据库创建者)的this回答:

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
        }
    }
}

1 个答案:

答案 0 :(得分:0)

与所有触发器一样,此触发器在服务器上调用,即在首先打开数据库的进程中使用自动混合模式(就像您一样)。因此,如果我首先启动“发件人”,那么我在那里得到以下输出:

sender starting
Sender: I change something...
Received: my message
Sender: I change something...
Received: my message

如果我然后启动“接收器”,我会收到以下消息:

Receiver: event received
Receiver: event received
Receiver: event received

如果您希望“接收器”可以显示更改的行,则需要不同的体系结构。例如,您可以向表中添加timestamp列(以及此列的索引),然后在接收方,查询时间戳为新的行。这仅适用于添加和更改的行;对于已删除的行,您可能需要添加一个包含自x时间以来已删除行的新表。该表需要不时地进行垃圾收集,以使其不会永远增长。