是否可以创建一个准备好的语句,然后在postgres下用Java重用它?
我正试着和博士后一起测试一些东西。我想知道是否可以创建并定义一个PreparedStatement,例如是否可以创建一个准备好的语句,然后在postgres下用Java重用它?,java,sql,postgresql,prepared-statement,Java,Sql,Postgresql,Prepared Statement,我正试着和博士后一起测试一些东西。我想知道是否可以创建并定义一个PreparedStatement,例如 String statement = "Insert into table_one values (?)"; PreparedStatement insert = con.prepareStatement(statement); insert.execute() // tell postgres to create this Prepared statement with
String statement = "Insert into table_one values (?)";
PreparedStatement insert = con.prepareStatement(statement);
insert.execute()
// tell postgres to create this Prepared statement without
尝试时,我收到一个错误,说明:SQLState:22023没有为参数1指定值
另外,如果我改为做以下事情
PreparedStatement insert = con.prepareStatement(statement);
insert.setInt(1, 10); //insert into table_one values (10);
insert.execute()
.... //commit other transactions to postgres
insert.setInt(1, 20);
insert.execute();
postgres是否会“记住”/已将上述内容注册为准备好的语句(我不是说缓存实际语句)?正如您的第二个代码片段所示,是的,您可以这样做 您可以创建一个preparedstatement,然后等待一段又一段时间,然后为传递的SQL字符串中的每个问号设置每个“参数”(例如调用
.setInt(1,…)
),并调用其中一个执行方法,然后。。。再等一段时间,然后再做一次,想做多少次就做多少次
preparedstatement的有效期与连接的有效期相同,或者直到您关闭它为止,您应该这样做。真正的麻烦在于:关闭它们您必须明确关闭它们。它们就像文件和网络套接字那样
如果你搞砸了,你的应用程序不会立即崩溃,测试也不会失败。然而,连接是永久性的“损坏”,因为它只能容纳有限数量的准备好的声明。当您不断地进行更多操作并且从不关闭它们时,最终会耗尽资源,并且会出现奇怪的SQL异常。你的应用程序是一颗滴答作响的定时炸弹。这是最糟糕的一类bug:很难测试,当事情变得繁忙时,不可避免地会爆炸你的应用程序。当bossman开始询问法律团队是否可以起诉你的重大过失时,你就会说:噢,也许我不应该玩弄那些导致错误的代码样式,这些错误不容易测试,很难发现,并且只会在事情繁忙时才引起问题
因此,遵循(严格的)协议以避免此类事情:
new SomeResource()
,或者通过一种非常清楚它是创建者的方法,例如文件.newInputStream
)必须由相同的代码关闭,或者,该代码必须是可关闭的资源try (PreparedStatement ps = ....) {
// use ps here, as often as you want....
} // ps is closed here
class WhateverTool implements AutoClosable {
private PreparedStatement ps; // long-lived
@Override public void close() throws SQLException {
if (ps != null) ps.close();
}
}
或者你这样做:
try (PreparedStatement ps = ....) {
// use ps here, as often as you want....
} // ps is closed here
class WhateverTool implements AutoClosable {
private PreparedStatement ps; // long-lived
@Override public void close() throws SQLException {
if (ps != null) ps.close();
}
}
而您与本课程的互动本身就是以以下形式进行的:
try (WhateverTool t = new WhateverTool()) {
// do whatever you want here...
} // but this is where it ends
在代码库中不允许有其他选项与资源交互
Java没有强制执行这一点,但如果不遵守这些规则,您肯定会遇到麻烦。当您在PostgreSQL JDBC驱动程序中使用
Java.sql.PreparedStatement
时,它首先不会在数据库服务器上创建真正的prepared语句,而只是构造一个简单的sql语句发送到数据库只有在第六次执行时,它才会认为值得在服务器上创建一个命名的prepared语句,以供将来执行时重用
您可以使用<代码>准备好的阈值>代码>连接属性来影响行为,请参见第二个示例使用服务器准备好的语句,您必须将阈值降低到0。只有当您知道您将重用所有已准备好的语句时,这才是有用的;比如避免SQL注入问题
在数据库服务器上有一个类似的功能:执行准备好的语句的前五次,PostgreSQL计算它的自定义计划。只有在第六次执行时,它才会考虑切换到一个通用的计划,这样才能避免从那时起计划的开销。这可以受到PostgreSQL语句的影响。从v12开始
因此,在默认设置下,需要执行十次
java.sql.PreparedStatement
,才能看到由于避免计划成本而提高的性能。是否可以使用参数化查询而不为所有参数提供值?否。是否可以重用准备好的查询(使用相同或其他值,如果它也是参数化的)?是的。我的问题更多的是postgres的问题。。postgres是保持preparestatement活动,还是它一直在发送消息,postgres只是按原样处理它。