如何使用 Postgres 数据库在 Java 中获得异步/事件驱动的 LISTEN/NOTIFY 支持?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21632243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:46:22  来源:igfitidea点击:

How do I get asynchronous / event-driven LISTEN/NOTIFY support in Java using a Postgres database?

javapostgresql

提问by jasons2645

From what I can tell, the JDBC drivers for LISTEN/NOTIFY in Java do NOT support true event-driven notifications. You have to poll the database every so often to see if there's a new notification.

据我所知,Java 中用于 LISTEN/NOTIFY 的 JDBC 驱动程序不支持真正的事件驱动通知。您必须经常轮询数据库以查看是否有新通知。

What options do I have in Java (possibly something other than JDBC?), if any, to get notifications asynchronously in a true event-driven manner without polling?

我在 Java 中有哪些选项(可能是 JDBC 之外的其他选项?),如果有的话,可以在没有轮询的情况下以真正的事件驱动方式异步获取通知?

采纳答案by Neil McGuigan

Use the pgjdbc-ng driver.

使用 pgjdbc-ng 驱动程序。

http://impossibl.github.io/pgjdbc-ng/

http://impossibl.github.io/pgjdbc-ng/

It supports async notifications, without polling. I have used it successfully.

它支持异步通知,无需轮询。我已经成功使用了。

See http://blog.databasepatterns.com/2014/04/postgresql-nofify-websocket-spring-mvc.html

http://blog.databasepatterns.com/2014/04/postgresql-nofify-websocket-spring-mvc.html

Oleg has a nice example answer as well

Oleg 也有一个很好的示例答案

回答by jasons2645

It appears as though there's no way around this. You can work around it, as several suggestions have been made along those lines, but ultimately, you're going to be polling.

似乎没有办法解决这个问题。您可以解决这个问题,因为已经按照这些方式提出了一些建议,但最终,您将进行投票。

回答by Lukas Eder

If you're OK with polling the database, here's how to do it:

如果您同意轮询数据库,请按以下步骤操作:

PGConnection con = ...

try (Statement s = con.createStatement()) {
    s.executeUpdate("listen x");
    s.executeUpdate("notify x, 'abc'");
}

for (PGNotification n : con.getNotifications()) {
    System.out.println(String.format("%s, %s, %s", 
        n.getPID(), n.getName(), n.getParameter()));
}

The above will yield something like:

以上将产生类似的东西:

11796, x, abc
11796, x, xyz

You have to run at least one statement to get new notifications from the connection.

您必须至少运行一条语句才能从连接中获取新通知。

回答by Oleg Mikhailov

Here's an asynchronous pattern using com.impossibl.postgres.api (pgjdbc-ng-0.6-complete.jar) with JDK 1.8:

这是使用 com.impossibl.postgres.api ( pgjdbc-ng-0.6-complete.jar) 和 JDK 1.8的异步模式:

import com.impossibl.postgres.api.jdbc.PGConnection;
import com.impossibl.postgres.api.jdbc.PGNotificationListener;
import com.impossibl.postgres.jdbc.PGDataSource;    
import java.sql.Statement;

public static void listenToNotifyMessage(){
    PGDataSource dataSource = new PGDataSource();
    dataSource.setHost("localhost");
    dataSource.setPort(5432);
    dataSource.setDatabase("database_name");
    dataSource.setUser("postgres");
    dataSource.setPassword("password");

    PGNotificationListener listener = (int processId, String channelName, String payload) 
        -> System.out.println("notification = " + payload);

    try (PGConnection connection = (PGConnection) dataSource.getConnection()){
        Statement statement = connection.createStatement();
        statement.execute("LISTEN test");
        statement.close();
        connection.addNotificationListener(listener);
        while (true){ }
    } catch (Exception e) {
        System.err.println(e);
    }
}

Create a trigger function for your database:

为您的数据库创建一个触发器函数:

CREATE OR REPLACE FUNCTION notify_change() RETURNS TRIGGER AS $$
    BEGIN
        SELECT pg_notify('test', TG_TABLE_NAME);
        RETURN NEW;
    END;
$$ LANGUAGE plpgsql;

Assign a trigger for every table you want to track:

为您要跟踪的每个表分配一个触发器:

CREATE TRIGGER table_change 
    AFTER INSERT OR UPDATE OR DELETE ON table_name
    FOR EACH ROW EXECUTE PROCEDURE notify_change();