在PostgreSQL中使用pg_notify触发函数

Tom*_*Tom 18 database postgresql notifications triggers plpgsql

我试图从PostgreSQL触发器函数发出通知.我可以成功使用NOTIFY命令,但我没有运气pg_notify.即使我从psql控制台调用pg_notify函数时收到通知,但在从触发器函数调用它时,我从未收到通知.

此版本的触发器功能按预期工作.我有一个听到'mymessage'的Java程序,它收到一个带有'NOTIFY'有效负载的通知.

-- Function: conversation_notify()

-- DROP FUNCTION conversation_notify();

CREATE OR REPLACE FUNCTION conversation_notify()
  RETURNS trigger AS
$BODY$
    BEGIN
        --SELECT pg_notify('mymessage', 'fired by FUNCTION');
        NOTIFY mymessage, 'fired by NOTIFY';
        RETURN NULL;
    END; 
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION conversation_notify() OWNER TO postgres;
Run Code Online (Sandbox Code Playgroud)

此版本的触发器功能无法按预期工作.唯一的变化是取消注释pg_notify行并注释掉下面的NOTIFY行.(我没有修改LISTENing的Java应用程序.)我希望我的应用程序LISTENing到'mymessage'应该收到'FUNCTION'有效负载的通知.实际行为是在修改相应表后30秒甚至没有收到任何内容.

-- Function: conversation_notify()

-- DROP FUNCTION conversation_notify();

CREATE OR REPLACE FUNCTION conversation_notify()
  RETURNS trigger AS
$BODY$
    BEGIN
        SELECT pg_notify('mymessage', 'fired by FUNCTION');
        --NOTIFY mymessage, 'fired by NOTIFY';
        RETURN NULL;
    END; 
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION conversation_notify() OWNER TO postgres;
Run Code Online (Sandbox Code Playgroud)

但是,我真的困惑,因为相同的pg_notify命令在psql控制台中按预期工作!当我执行以下命令时,我的Java应用程序会收到一个带有'由CONSOLE触发'的有效负载的通知:

select pg_notify('mymessage', 'fired by CONSOLE');
Run Code Online (Sandbox Code Playgroud)

为了完整性,这是我的触发器定义:

-- Trigger: conversation_notify on ofconversation

-- DROP TRIGGER conversation_notify ON ofconversation;

CREATE TRIGGER conversation_notify
  AFTER INSERT OR UPDATE
  ON ofconversation
  FOR EACH ROW
  EXECUTE PROCEDURE conversation_notify();
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用pg_notify,因为我希望有一个动态有效负载.现在,这是一个有争议的问题.:) Postgres 9.0手册表明这应该是可能的.'payload'参数状态的NOTIFY文档:

(如果需要传递二进制数据或大量信息,最好将其放在数据库表中并发送记录的密钥.)

我还引用了一个相关的Stack Overflow问题,我想我已经躲过了这个问题:在PostgreSQL中使用pg_notify(text,text)进行LISTEN/NOTIFY.

数据库版本是:

PostgreSQL 9.0.3,由Visual C++编译构建1500,32位

我的操作系统是Windows XP Professional,2002版,SP3.

提前致谢.

编辑:在下面添加了我的Java监听器代码.它基于PostgreSQL文档中的这个示例:http://jdbc.postgresql.org/documentation/81/listennotify.html.

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.postgresql.PGConnection;
import org.postgresql.PGNotification;

public class ConversationListener extends Thread
{   
    private Connection conn;
    private PGConnection pgConn;

    public ConversationListener(Connection conn) throws SQLException
    {
        this.conn = conn;
        this.pgConn = (PGConnection) conn;
        Statement listenStatement = conn.createStatement();
        listenStatement.execute("LISTEN mymessage");
        listenStatement.close();
    }

    @Override
    public void run()
    {
        while (true)
        {
            try
            {
                // issue a dummy query to contact the backend
                // and receive any pending notifications.
                Statement selectStatement = conn.createStatement();
                ResultSet rs = selectStatement.executeQuery("SELECT 1");
                rs.close();
                selectStatement.close();

                PGNotification notifications[] = pgConn.getNotifications();

                if (notifications != null)
                {
                    for (PGNotification pgNotification : notifications)
                    {
                        System.out.println("Got notification: " + pgNotification.getName() +
                            " with payload: " + pgNotification.getParameter());
                    }
                }

                // wait a while before checking again
                Thread.sleep(500);
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            catch (InterruptedException ie)
            {
                ie.printStackTrace();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个简单的Java 1.6 SE桌面应用程序,因此我正在管理自己的JDBC连接和所有内容.我正在加载驱动程序

Class.forName("org.postgresql.Driver");
Run Code Online (Sandbox Code Playgroud)

我正在使用postgresql-9.0-801.jdbc3.jar库(我的类路径中只有一个)和JDK 1.6.0_22.

仅从上面回顾一下,Java代码可以正常使用来自psql和触发器的NOTIFY,以及来自psql的pg_notify.

CJC*_*ink 28

这可能是迟到的帮助,但也许其他人将能够使用它.使用SELECT pg_notify('',''); 在触发器中导致DB响应

ERROR: query has no destination for result data
SQL state: 42601
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Run Code Online (Sandbox Code Playgroud)

将错误更改为PERFORM有助于解决此问题,并按预期交付通知.也许这可能是问题所在.

我有相同的设置,并有同样的问题.


Oto*_*lez 14

对那里的人来说可能有用.有时您希望将整行传递给"观察者",然后将整行序列化为JSON可能是个不错的主意.您可以在row_to_json的帮助下实现此目的

-- Notify when record was inserted into 'prices' table
CREATE OR REPLACE FUNCTION notify_pricesinserted()
  RETURNS trigger AS $$
DECLARE
BEGIN
  PERFORM pg_notify(
    CAST('pricesinserted' AS text),
    row_to_json(NEW)::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER notify_pricesinserted
  AFTER INSERT ON prices
  FOR EACH ROW
  EXECUTE PROCEDURE notify_pricesinserted();
Run Code Online (Sandbox Code Playgroud)

  • 为什么“CAST('pricesinserted' AS text)”仅仅“'pricesinserted'”也有效?(为我)。 (2认同)

Inv*_*ble 7

CREATE OR REPLACE FUNCTION notifyshipment() RETURNS trigger AS $$
DECLARE
BEGIN
  PERFORM pg_notify(CAST('snc' AS text),CAST(NEW.id AS text)|| ' ' || CAST(NEW.tracking_number AS text));
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER shipmentnotify AFTER UPDATE ON shipments FOR EACH ROW EXECUTE PROCEDURE notifyshipment();
Run Code Online (Sandbox Code Playgroud)