2017-06-23 33 views
4

我遇到PostgreSQL JDBC驅動程序最新版本的問題:當準備好的語句仍在執行時,我無法收集警告/通知。警告列表僅在語句返回後纔可用。如何在JDBC語句執行時收集警告/通知?

我用一些以前的驅動程序版本(我猜9.1)使用此功能,但PgPreparedStatement實施後可能已改變。

在結果返回之前,我有哪些選項可以收集警告?

我建立這個簡單的測試:

public class WarningTest { 

    @Test 
    public void readWarnings() throws Exception { 
     Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/test_db", "test_user", "test_password"); 
     createTestFunction(con); 

     PreparedStatement statement = con.prepareStatement("SELECT test_function();"); 
     SQLWarning[] warnings = new SQLWarning[1]; 
     new Timer().schedule(new TimerTask() { 
      @Override public void run() { 
       try { 
        warnings[0] = statement.getWarnings(); 
       } catch (SQLException e) { 
        Assert.fail("Exception thrown: " + e.getMessage()); 
       } 
      } 
     }, 3500); 
     statement.executeQuery(); 
     Thread.sleep(1000); 
     statement.close(); 

     Assert.assertNotNull(warnings[0]); 
     Assert.assertFalse(warnings[0].getMessage().isEmpty()); 
    } 

    private void createTestFunction(Connection con) throws SQLException { 
     final PreparedStatement statement = con.prepareStatement(
      "CREATE OR REPLACE FUNCTION test_function() RETURNS VOID AS\n" 
      + "$BODY$\n" 
      + "BEGIN\n" 
      + "\tFOR i IN 1..3 LOOP \n" 
      + "\t\tRAISE NOTICE 'Tick %', i;\n" 
      + "\t\tEXECUTE pg_sleep(1);\n" 
      + "\tEND LOOP;\n" 
      + "END\n" 
      + "$BODY$\n" 
      + "\tLANGUAGE plpgsql STABLE;"); 
     statement.execute(); 
     statement.close(); 
    } 
} 

它創建3秒運行,並在每個第二的起點寫入蜱的功能。

測試通過像這樣的計時器在結果返回後啓動。但是,如果將定時器延遲從3500減少到1500,那麼即使數據庫在那段時間發出了2個通知,測試也會失敗。

回答

7

REL9.4.1210版本REL9.4.1209及以下版本引入此問題按預期工作。

Line 244 of this commit就是這個不再有效的原因,一旦收到警告,警告就會直接添加到聲明中,但它已被重新考慮,現在它們僅在完成後纔可用。

I have raised an issue for this,以及一個PR to address it.

+0

我一直在看你的GitHub上的努力。賞金是當之無愧的! –

+0

@BorisSchegolev該更改已合併,應在下一個驅動程序版本。 – Magnus