我正在尝试从 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;
我的触发函数的这个版本无法按预期工作。唯一的更改是取消注释 pg_notify 行并注释掉下面的 NOTIFY 行。 (我没有修改正在侦听的 Java 应用程序。)我希望侦听“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;
但是,我真的很困惑,因为相同的 pg_notify 命令在 psql 控制台中按预期工作!当我执行以下命令时,我的 Java 应用程序收到带有“由 CONSOLE 触发”有效负载的通知:
select pg_notify('mymessage', 'fired by CONSOLE');
为了完整起见,这是我的触发器定义:
-- 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();
我正在尝试使用 pg_notify 因为我想要一个动态负载。现在,这是一个有争议的问题。 :) Postgres 9.0 手册表明这应该是可能的。 “payload”参数状态的 NOTIFY 文档:
(如果需要通信二进制数据或者大量信息,最好放在数据库表中,并发送记录的key。)
我还引用了一个相关的堆栈溢出问题,我想我已经回避了这个问题:LISTEN/NOTIFY using pg_notify(text, text) in PostgreSQL。
数据库版本为:
PostgreSQL 9.0.3,由 Visual C++ build 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();
}
}
}
}
这是一个简单的 Java 1.6 SE 桌面应用程序,因此我正在管理自己的 JDBC 连接和一切。我正在通过
加载驱动程序Class.forName("org.postgresql.Driver");
我正在使用 postgresql-9.0-801.jdbc3.jar 库(我的类路径上只有一个)和 JDK 1.6.0_22。
回顾一下上面的内容,Java 代码可以与 psql 中的 NOTIFY 和触发器以及 psql 中的 pg_notify 一起正常工作。
这可能为时已晚,但也许其他人能够使用它。 使用 SELECT pg_notify('', '');触发器中导致数据库响应
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.
按照错误提示将 SELECT 更改为 PERFORM 有助于解决此问题,并且通知将按预期发送。也许这可能就是问题所在。
我有相同的设置,并且遇到了相同的问题。
这可能对外面的人有用。有时您想将整行传递给“观察者”,然后将整行序列化为 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();
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();
您可以直接在创建触发器函数中使用以下代码:
EXECUTE 'NOTIFY your_declared_notify';
或
PERFORM pg_notify(CAST('your_declared_notify' AS text), CAST(NEW.name AS text));
我不知道这些是否有助于解决您的问题,但我遇到的一些问题是:
LISTEN
命令提交事务。我对Java不熟悉,不知道你是否处于自动提交模式。pg_notify
的事务没有提交或被回滚?但是,这些都不能解释为什么 NOTIFY 有效而 pg_notify 无效。
也许您会喜欢以下语法:
RAISE notice 'hstore %, patrm %, dt %, v% ', new_g, _param_id, _dt, new.v ;