如何在执行 JDBC 语句时收集 warnings/notices?
How to collect warnings/notices while JDBC statement is being executed?
我在使用最新版本的 PostgreSQL JDBC 驱动程序时遇到问题:我无法收集 warnings/notices 准备好的语句仍在执行中。警告列表仅在语句 returns.
后可用
我在一些以前的驱动程序版本(我猜是 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 个通知,测试也会失败。
此问题是 REL9.4.1210
引入的。 REL9.4.1209
及以下版本按预期工作。
Line 244 of this commit 是这个不再起作用的原因,之前警告是一收到就直接添加到语句中,但它被重构了,现在只有在完成后才能使用。
I have raised an issue for this, as well as a PR to address it.
我在使用最新版本的 PostgreSQL JDBC 驱动程序时遇到问题:我无法收集 warnings/notices 准备好的语句仍在执行中。警告列表仅在语句 returns.
后可用我在一些以前的驱动程序版本(我猜是 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 个通知,测试也会失败。
此问题是 REL9.4.1210
引入的。 REL9.4.1209
及以下版本按预期工作。
Line 244 of this commit 是这个不再起作用的原因,之前警告是一收到就直接添加到语句中,但它被重构了,现在只有在完成后才能使用。
I have raised an issue for this, as well as a PR to address it.