【问题标题】:H2 Trigger, Notifier not called in Automatic Mixed Mode (AUTO_SERVER=TRUE) on remote clientH2 触发器,未在远程客户端上以自动混合模式 (AUTO_SERVER=TRUE) 调用通知程序
【发布时间】:2013-10-11 13:13:59
【问题描述】:

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

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

【问题讨论】:

    标签: java h2


    【解决方案1】:

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

    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
    

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

    【讨论】:

    • 您可以将所有条目保存在一个链表中,或者(也许更好)一个 TreeMap。这样你就不需要任何桌子了。发送者和接收者都可以使用用户定义的函数;一个叫send,另一个叫receive。这将减少开销。
    • 我不同意您上面的回答,如果我首先将发件人作为服务器启动,他当然会收到收到的消息通知,因为他收到了触发器,但是如果我随后启动一个接收器(他是一个客户,所以他不会收到任何触发器)这个不会收到任何事件!您能告诉我所有客户端如何从数据库插入中接收事件吗?谢谢
    • 这是一个新要求(你之前没有写过)。好吧,你需要使用一个队列(可能是一个持久队列)。
    • 我更新了问题以使其更直接,问题相同,只是解释得更好:)。带有时间戳和消息的表完全没问题,所以我认为不需要队列,我想念如何通知客户表中的新内容。触发器是不够的,因为它只通知 H2 服务器,用户定义的函数我无法理解当表中发生变化时如何在每个客户端上调用它。
    • 好吧,看看my answer for your other question。用户定义的函数需要在之前进行某些更改。一旦有一些变化,用户定义的函数就会返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 1970-01-01
    • 2016-10-03
    相关资源
    最近更新 更多