Utilizando pg_notify en la función de activación de PostgreSQL
Estoy intentando emitir una notificación desde una función de activación de PostgreSQL. Puedo usar con éxito el comando NOTIFICAR, pero no tengo suerte con pg_notify. Aunque recibo una notificación cuando invoco la función pg_notify desde la consola psql, nunca recibo una notificación cuando invoco lo mismo desde mi función de activación.
Esta versión de mi función de activación funciona como se esperaba. Tengo un programa Java que ESCUCHA 'mymessage' y recibe una notificación con una carga útil 'disparada por 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;
Esta versión de mi función de activación NO funciona como se esperaba. Los únicos cambios son descomentar la línea pg_notify y comentar la línea NOTIFY a continuación. (No modifiqué la aplicación Java que está ESCUCHANDO.) Espero que mi aplicación que ESCUCHE 'mymessage' reciba una notificación con una carga útil 'activada por FUNCTION'. El comportamiento real es que no se recibe nada, incluso más de 30 segundos después de que se modifica la tabla correspondiente.
-- 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;
Sin embargo, soyDe Verda confundido, porque el mismo comando pg_notify funciona como se esperaba de la consola psql! Cuando ejecuto el siguiente comando, mi aplicación Java recibe una notificación con una carga útil 'activada por CONSOLA':
select pg_notify('mymessage', 'fired by CONSOLE');
Para completar, aquí está mi definición de disparador:
-- 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();
Estoy tratando de usar pg_notify porque me gustaría tener una carga dinámica. En este momento, ese es un punto discutible. :) El manual de Postgres 9.0 indica que esto debería ser posible. @ Los documentos de NOTIFICACIÓN para el estado del parámetro 'carga útil':
(Si es necesario comunicar datos binarios o grandes cantidades de información, es mejor ponerlos en una tabla de base de datos y enviar la clave del registro).
También hice referencia a una pregunta relacionada con el desbordamiento de pila, y creo que he esquivado este problema: ESCUCHAR / NOTIFICAR usando pg_notify (texto, texto) en PostgreSQL.
La versión de la base de datos es:
PostgreSQL 9.0.3, compilado por Visual C ++ build 1500, 32 bits
Mi OS es Windows XP Professional, Versión 2002, SP3.
Gracias por adelantado
EDIT: Agregué mi código de escucha Java a continuación. Se basa en este ejemplo de los documentos de PostgreSQL:http: //jdbc.postgresql.org/documentation/81/listennotify.htm.
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();
}
}
}
}
Esta es una aplicación de escritorio Java 1.6 SE simple, por lo que estoy administrando mi propia conexión JDBC y todo. Estoy cargando el controlador a través de
Class.forName("org.postgresql.Driver");
Estoy usando la biblioteca postgresql-9.0-801.jdbc3.jar (solo una en mi classpath) y JDK 1.6.0_22.
Solo para recapitular desde arriba, el código Java funciona bien con NOTIFY de psql y el disparador, y con pg_notify de psql.