Я пытаюсь выдать уведомление из триггерной функции PostgreSQL. Я могу успешно использовать команду NOTIFY, но мне не повезло с pg_notify. Несмотря на то, что я получаю уведомление, когда я вызываю функцию pg_notify из консоли psql, я никогда не получаю уведомление при вызове того же самого из моей триггерной функции.
Эта версия моей триггерной функции работает, как ожидалось. У меня есть Java-программа, которая LISTENing на "mymessage", и получает уведомление с "полезной нагрузкой 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, которое является LISTENING.) Я ожидаю, что мое приложение 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;
Однако я действительно смущен, потому что такая же команда 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 указывает, что это должно быть возможно. Документы NOTIFY для состояния параметра "полезная нагрузка":
(Если необходимо передать двоичные данные или большие объемы информации, лучше всего поместить их в таблицу базы данных и отправить ключ записи.)
Я также ссылался на связанный с этим вопрос о переполнении стека, и я думаю, что я уклонился от этой проблемы: LISTEN/NOTIFY с помощью pg_notify (текст, текст) в PostgreSQL.
Версия базы данных:
PostgreSQL 9.0.3, скомпилированный Visual С++ build 1500, 32-разрядный
Моя ОС - Windows XP Professional, версия 2002, SP3.
Спасибо заранее.
EDIT: Добавлен код прослушивания 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 отлично работает с NOTIFY из psql и триггера, а с pg_notify из psql.