Sid*_*kha 9 java postgresql database-connection connection-pooling pg-jdbc
我正在使用PostgreSQL DB并应用它的LISTEN/NOTIFY功能.所以我的监听器在我的AS(应用服务器)上,并且我在我的数据库上配置了触发器,这样当在表上执行CRUD操作时,NOTIFY在AS上发送请求.
java中的LISTENER类:
@Singleton
@Startup
NotificationListenerInterface.class)
public class NotificationListener extends Thread implements NotificationListenerInterface {
@Resource(mappedName="java:/RESOURCES")
private DataSource ds;
@PersistenceContext(unitName = "one")
EntityManager em;
Logger logger = Logger.getLogger(NotificationListener.class);
private Connection Conn;
private PGConnection pgConnection = null;
private NotifyRequest notifyRequest = null;
@PostConstruct
public void notificationListener() throws Throwable {
System.out.println("Notification****************");
try
{
Class.forName("com.impossibl.postgres.jdbc.PGDriver");
String url = "jdbc:pgsql://192.xx.xx.126:5432/postgres";
Conn = DriverManager.getConnection(url,"postgres","password");
this.pgConnection = (PGConnection) Conn;
System.out.println("PG CONNECTON: "+ pgConnection);
Statement listenStatement = Conn.createStatement();
listenStatement.execute("LISTEN notify_channel");
listenStatement.close();
pgConnection.addNotificationListener(new PGNotificationListener() {
@Override
public void notification(int processId, String channelName, String payload){
System.out.println("*********INSIDE NOTIFICATION*************");
System.out.println("Payload: " + jsonPayload);
}
Run Code Online (Sandbox Code Playgroud)
因此,当我的AS启动时,我已经配置了在启动时调用侦听器类(@Startup annotation)并且它开始在通道上侦听.
现在这样可以正常工作,如果说测试我手动编辑DB中的表,生成通知并且LISTENER接收它.
但是,当我以编程方式在表上发送UPDATE请求时,UPADTE成功执行但LISTENER没有收到任何内容.
当我发送请求时,我觉得我的LISTENER连接断开了(它也与编辑实体建立了连接),但我不确定.我读到了永久连接和汇集连接,但无法决定如何实现这一点.
我正在使用pgjdbc(http://impossibl.github.io/pgjdbc-ng/)jar作为异步通知,因为jdbc连接需要轮询.
编辑:
当我使用标准的jdbc jar(而不是pgjdbc)通过轮询尝试上面的监听器时,我收到通知.
我这样做
PGNotification notif[] = con.getNotifications()
,我收到通知,但是如下所示异步,我没有收到通知.
pgConnection.addNotificationListener(new PGNotificationListener() {
@Override
public void notification(int processId, String channelName, String payload){
System.out.println("*********INSIDE NOTIFICATION*************");
}
Run Code Online (Sandbox Code Playgroud)
解决了:
我的听众是走出去的范围在函数执行完毕后,我的听众有功能范围.所以将它保存到我的启动bean类的成员变量中然后它工作.
通知侦听器由该库在内部维护为弱引用,这意味着您必须在外部持有硬引用,以便它们不会被垃圾回收.查看BasicContext类的第642 - 655行:
public void addNotificationListener(String name, String channelNameFilter, NotificationListener listener) {
name = nullToEmpty(name);
channelNameFilter = channelNameFilter != null ? channelNameFilter : ".*";
Pattern channelNameFilterPattern = Pattern.compile(channelNameFilter);
NotificationKey key = new NotificationKey(name, channelNameFilterPattern);
synchronized (notificationListeners) {
notificationListeners.put(key, new WeakReference<NotificationListener>(listener));
}
}
Run Code Online (Sandbox Code Playgroud)
如果GC选择了你的监听器,那么对弱引用的"get"调用将返回null并且不会从第690 - 710行看到
@Override
public synchronized void reportNotification(int processId, String channelName, String payload) {
Iterator<Map.Entry<NotificationKey, WeakReference<NotificationListener>>> iter = notificationListeners.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<NotificationKey, WeakReference<NotificationListener>> entry = iter.next();
NotificationListener listener = entry.getValue().get();
if (listener == null) {
iter.remove();
}
else if (entry.getKey().channelNameFilter.matcher(channelName).matches()) {
listener.notification(processId, channelName, payload);
}
}
}
Run Code Online (Sandbox Code Playgroud)
要解决此问题,请添加通知侦听器:
/// Do not let this reference go out of scope!
PGNotificationListener listener = new PGNotificationListener() {
@Override
public void notification(int processId, String channelName, String payload) {
// interesting code
};
pgConnection.addNotificationListener(listener);
Run Code Online (Sandbox Code Playgroud)
在我看来,弱引用的用例相当奇怪......
| 归档时间: |
|
| 查看次数: |
2158 次 |
| 最近记录: |