8

PostgreSQL DB를 사용하고 있으며 해당 기능을 LISTEN/NOTIFY에 적용하고 있습니다. 그래서 내 청취자가 내 AS (응용 프로그램 서버)에 있고 테이블에 CRUD 작업이 수행 될 때 NOTIFY 요청이 AS에 전송되도록 내 DB에 트리거가 구성되어 있습니다.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 항아리를 사용하여 폴링와 위의 리스너를하려고하면 (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 상태에서 두 개의 연결 (이전 하나는 새로운 하나)을 제공했습니다 :'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

통지 청취자는 해당 라이브러리가 내부적으로 약한 참조로 유지 관리하므로 하드 참조가 외부에서 가비지 수집되지 않도록 외부에 보관해야합니다. - 710

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

} 

GC가, 리스너를 집어 들고는 null를 돌려줍니다 약한 참조의 "수"를 호출 라인에서 690를 볼 때 해고하지 않을 경우 : 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