簡體   English   中英

通知postgres對java應用程序的更改

[英]Notifying postgres changes to java application

問題

我正在為幾十萬種產品建立一個postgres數據庫 我將設置一個索引(Solr或ElasticSearch)來改善復雜搜索查詢的查詢時間。

現在的重點是如何讓索引與數據庫同步?

在過去, 我有一種應用程序定期輪詢數據庫以檢查應該完成的更新 ,但是我會有一個過時的索引狀態時間 (從數據庫更新到索引更新拉動)。

我更喜歡一種解決方案,數據庫會通知我的應用程序 (java應用程序)數據庫中已經更改了某些內容,此時應用程序將決定是否需要更新索引。 為了更准確,我將構建一種生產者和消費者結構,希望副本將從postgres接收有關更改的通知,如果這與索引的數據相關,則將其存儲在待執行更新的堆棧中。 消費者將使用此堆棧並構建要存儲到索引中的文檔。

可能的解決方案

一種解決方案是編寫一種副本端點 ,其中應用程序將表現為用於從原始數據庫復制數據的postgres實例。 有人對這種方法有一些經驗嗎?

我對此問題有哪些其他解決方案?

我對此問題有哪些其他解決方案?

使用LISTENNOTIFY告訴您的應用程序已發生變化。

您可以從也記錄隊列表中的更改的觸發器發送NOTIFY

你需要一個PgJDBC連接,它已經為你正在使用的事件發送了一個LISTEN 如果您使用SSL,它必須通過定期發送空查詢( "" )來輪詢數據庫; 如果您不使用SSL,則可以通過使用異步通知檢查來避免這種情況。 您需要從連接池中解包Connection對象,以便能夠將基礎連接轉換為PgConnection以使用listen / notify。 相關答案

生產者/消費者的位將更難。 要在PostgreSQL中擁有多個崩潰安全並發使用者,您需要使用pg_try_advisory_lock(...)咨詢鎖定。 如果你不需要並發消費者那么這很容易,你只需要SELECT ... LIMIT 1 FOR UPDATE一行。

希望9.4將包含一個更簡單的方法來跳過具有FOR UPDATE鎖定行,因為它正在開發中。

要使用postgres的LISTEN和NOTIFY,您需要使用可支持異步通知的驅動程序。 postgres JDBC驅動程序不支持異步通知。

要不斷地從Application Server通過一個頻道,請轉到pgjdbc-ng 0.6驅動程序。

http://impossibl.github.io/pgjdbc-ng/

它支持異步通知,無需輪詢。

一般來說,我建議使用EAI模式實現松散耦合。 然后,如果您決定交換數據庫,則索引端的代碼不會更改。

如果你想堅持緊耦合,我建議使用LISTEN / NOTIFY 在Java中,使用pgjdbc-ng驅動程序很重要,因為它支持沒有輪詢的異步通知。

這是一個異步模式(基於這個答案 ):

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);
        // it only works if the connection is open. Therefore, we do an endless loop here.
        while (true) {
           Thread.sleep(500);
       }
    } catch (Exception e) {
        System.err.println(e);
    }
}

在其他語句中,您現在可以執行NOTIFY test, 'This is a payload'; 您還可以在觸發器等中執行NOTIFY

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM