8

私はPostgreSQL DBを使用しており、その機能をLISTEN/NOTIFYに適用しています。だから私のリスナーは私のAS(Application Server)にあり、CRUD操作がテーブル上で実行されたときにNOTIFY要求がAS上で送信されるように、自分のDB上に設定されたトリガーを持っています。 JavaでLISTEN/NOTIFY pgconnectionがjavaになる?

LISTENERクラス:私のASがアップしているよう

 @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); 

} 

だから、私は起動時にリスナークラスは(@Startup annotation)と呼ばれていることを設定して、それがチャネル上でリスニングを開始です。

これはうまくいけば、テスト用に私のテーブルをDBで手動で編集すると通知が生成され、LISTENERがそれを受け取るとうまくいきます。

ただし、プログラムでテーブルのUPDATE要求を送信すると、UPADTEは正常に実行されますが、LISTENERは何も受信しません。

リクエストを送信したときにリスナーとの接続が切断されていると感じましたが(エンティティの編集にも接続します)、わかりません。永続的な接続とプールされた接続については読んだが、それを追求する方法を決めることはできなかった。

jdbc接続でポーリングが必要なため、非同期通知用にpgjdbc(http://impossibl.github.io/pgjdbc-ng/)jarを使用しています。

編集:私は、標準の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*************"); 
     } 

解決しよう:私のリスナーは関数スコープを持っていたとして、機能の実行が完了した後、マイリスナーがスコープの外に行っていた

。そこで私のスタートアップのBeanクラスのメンバ変数に入れておき、それがうまくいきました。

+0

リスナーの内部で、変数 'jsonPayload'が存在しません。また、アップデートを書き込むために同じ接続を使用していますか?アタッチされたリスナーとの接続が有効範囲外になり、GCによって破棄される可能性があります。 –

+0

私は同じ接続を使用していません。しかし、 'netstat'を使って接続が確立された状態にあること、すなわち古い接続が失われていないことを確認しました。 'netstat --numeric-ports | grep 5432 | grep my.ip'はESTABLISHED状態の2つの接続(古いものと新しいもの)を与えました:' tcp 0 0 192.168.5.126:5432 192.168.105.213:46802 ESTABLISHED tcp 0 0 192.168.5.126:5432 192.168.105.213:46805 ESTABLISHED' –

+0

@ LukeA.Leber:質問の編集を確認してください。 –

答えて

5

通知リスナーはそのライブラリによって内部的に弱い参照として管理されているため、外部参照を保持してガベージコレクションされないようにする必要があります。 GCは、あなたのリスナーを拾った場合

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)); 
    } 

} 

、弱参照の「取得」の呼び出しはnullを返しますし、ライン690から分かるように起動しません - 710

:655 - BasicContextクラスライン642をチェック以下のようなあなたの通知リスナを追加し、この問題を解決するには
@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); 
     } 

    } 

} 

/// 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); 

私の意見では弱い参照のための非常に奇妙なユースケースを...

+0

ありがとう、あなたは私の日を救った。私はこれに非常に混乱していた – sanket1729

関連する問題