关于java:通过JDBC将DDL与SELECT混合时,“错误:缓存的计划不得更改结果类型”

“ERROR: cached plan must not change result type” when mixing DDL with SELECT via JDBC

我在JDBC上遇到了一个与PostgreSQL有关的有趣问题(暂时无法在JDBC之外重现它),

"ERROR: cached plan must not change result type"

重现此问题的最简单方法是使用以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Connection c = getConnection();
c.setAutoCommit(true);
List<String> statements = Arrays.asList(
   "create table t(a int)",
   "select * from t",
   "alter table t add b int",
   "select * from t",
   "alter table t add c int",
   "select * from t",
   "alter table t add d int",
   "select * from t",
   "alter table t add e int",
   "select * from t",
   "alter table t add f int",
   "select * from t"
);

for (String statement : statements)
    try (PreparedStatement s = c.prepareStatement(statement)) {
        System.out.println(s);
        s.execute();
    }

以下代码可以正常工作的事实使我假设这是JDBC驱动程序中的一个非常微妙的错误(请注意,我只是在批处理中删除了第六条DDL语句):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Connection c = getConnection();
c.setAutoCommit(true);
List<String> statements = Arrays.asList(
   "create table t(a int)",
   "select * from t",
   "alter table t add b int",
   "select * from t",
   "alter table t add c int",
   "select * from t",
   "alter table t add d int",
   "select * from t",
   "alter table t add e int",
   "select * from t"
);

for (String statement : statements)
    try (PreparedStatement s = c.prepareStatement(statement)) {
        System.out.println(s);
        s.execute();
    }

似乎可以通过DISCARD ALL丢弃所有缓存的计划,但这会使情况变得更糟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Connection c = getConnection();
c.setAutoCommit(true);
List<String> statements = Arrays.asList(
   "create table t(a int)",
   "select * from t",
   "alter table t add b int",
   "select * from t",
   "alter table t add c int",
   "select * from t",
   "alter table t add d int",
   "select * from t",
   "alter table t add e int",
   "select * from t",
   "alter table t add f int",
   "discard all",
   "select * from t"
);

for (String statement : statements)
    try (PreparedStatement s = c.prepareStatement(statement)) {
        System.out.println(s);
        s.execute();
    }

我遇到另一个错误消息

"ERROR: prepared statement"S_1" doesn't exist"

有谁知道解决方法? 还是记录此错误的指针? 有趣的是,它似乎与默认的准备阈值5有关


这似乎与PostgreSQL的PREPARE_THRESHOLD有关,对于JDBC驱动程序,该默认值为5。

将其设置为零将解决/解决此特定问题:

1
 ((PGConnection) connection).setPrepareThreshold(0);

此堆栈溢出问题中也提供了更多信息


禁用准备好的语句对于解决此问题来说太过严厉了。 现在,您可以通过在pgjdbc连接设置上设置autosave=conservative来解决特定问题,请参阅:https://stackoverflow.com/a/48536394/924597