如何在执行 JDBC 语句时收集警告/通知?

Posted

技术标签:

【中文标题】如何在执行 JDBC 语句时收集警告/通知?【英文标题】:How to collect warnings/notices while JDBC statement is being executed? 【发布时间】:2017-06-23 12:40:19 【问题描述】:

我在使用最新版本的 PostgreSQL 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 个通知,测试也会失败。

【问题讨论】:

【参考方案1】:

REL9.4.1210 引入了此问题。 REL9.4.1209 及以下版本按预期工作。

Line 244 of this commit 是这不再起作用的原因,以前收到警告后就直接将其添加到语句中,但它已被重构,现在它们仅在完成后可用。

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

【讨论】:

我一直在关注你在 GitHub 上的努力。赏金当之无愧! @BorisSchegolev 更改已合并,应该在下一个驱动程序版本中。

以上是关于如何在执行 JDBC 语句时收集警告/通知?的主要内容,如果未能解决你的问题,请参考以下文章

每当 MySQL 抛出警告时,我如何通知 sqlalchemy 引发错误?

执行上一个语句之前会显示Javascript警告框

java jdbc 执行sql语句批量操作问题

使用jdbc操作时,如何提取数据的性能

如何得到JDBC Insert 语句执行后插入Oracle 数据库记录的主键

如何确保在应用程序终止后*发送 iOS 本地通知