prepared - ¿Cómo obtengo el soporte LISTEN/NOTIFY asíncrono/controlado por eventos en Java usando una base de datos de Postgres?
login java postgresql (4)
Por lo que puedo decir, los controladores JDBC para LISTEN / NOTIFICAR en Java NO admiten las verdaderas notificaciones controladas por eventos. Tienes que sondear la base de datos cada cierto tiempo para ver si hay una nueva notificación.
¿Qué opciones tengo en Java (posiblemente otra que no sea JDBC), si las hay, para recibir notificaciones de forma asincrónica de una manera real basada en eventos sin sondeo?
Aquí hay un patrón asíncrono que usa com.impossibl.postgres.api ( pgjdbc-ng-0.6-complete.jar ) con 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);
}
}
Cree una función de disparo para su base de datos:
CREATE OR REPLACE FUNCTION notify_change() RETURNS TRIGGER AS $$
BEGIN
SELECT pg_notify(''test'', TG_TABLE_NAME);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Asigne un desencadenante para cada tabla que desee rastrear
CREATE TRIGGER table_change
AFTER INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE notify_change();
Parece que no hay forma de evitar esto. Puede solucionarlo, ya que se han hecho varias sugerencias en ese sentido, pero en última instancia, va a realizar una encuesta.
Si estás de acuerdo con sondear la base de datos, aquí tienes cómo hacerlo:
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()));
}
Lo anterior dará como resultado algo como:
11796, x, abc
11796, x, xyz
Debe ejecutar al menos una declaración para obtener nuevas notificaciones de la conexión.
Utilice el controlador pgjdbc-ng.
http://impossibl.github.io/pgjdbc-ng/
Admite notificaciones asíncronas, sin sondeo. Lo he utilizado con éxito.
Consulte http://blog.databasepatterns.com/2014/04/postgresql-nofify-websocket-spring-mvc.html
Oleg tiene un buen ejemplo de respuesta también.