![](/img/trans.png)
[英]Getting Postgres Database changes into Java application with Logical Replication
[英]Notifying postgres changes to java application
我正在為幾十萬種產品建立一個postgres數據庫 。 我將設置一個索引(Solr或ElasticSearch)來改善復雜搜索查詢的查詢時間。
現在的重點是如何讓索引與數據庫同步?
在過去, 我有一種應用程序定期輪詢數據庫以檢查應該完成的更新 ,但是我會有一個過時的索引狀態時間 (從數據庫更新到索引更新拉動)。
我更喜歡一種解決方案,數據庫會通知我的應用程序 (java應用程序)數據庫中已經更改了某些內容,此時應用程序將決定是否需要更新索引。 為了更准確,我將構建一種生產者和消費者結構,希望副本將從postgres接收有關更改的通知,如果這與索引的數據相關,則將其存儲在待執行更新的堆棧中。 消費者將使用此堆棧並構建要存儲到索引中的文檔。
一種解決方案是編寫一種副本端點 ,其中應用程序將表現為用於從原始數據庫復制數據的postgres實例。 有人對這種方法有一些經驗嗎?
我對此問題有哪些其他解決方案?
我對此問題有哪些其他解決方案?
使用LISTEN
和NOTIFY
告訴您的應用程序已發生變化。
您可以從也記錄隊列表中的更改的觸發器發送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.