创建preparedstatement的多个实例
Posted
技术标签:
【中文标题】创建preparedstatement的多个实例【英文标题】:Creating multiple instances of preparedstatement 【发布时间】:2016-03-11 10:27:57 【问题描述】:我是 jdbc 编程的新手。我正在多次创建PreparedStatement
的实例并将其分配给相同的引用变量。在创建PreparedStatement
的第二个实例之前,我是否需要关闭PreparedStatement
的第一个实例?
oPrepStmt = oRoot.con.prepareStatement(strSql);
if (strProviderType.length() > 0)
strSql += " and users.usertype IN (?)";
// DO I need to close prepare statement, before creating another instance of preparestatement and assigning to same reference variable.
// i.e. oPrepStmt.close();
oPrepStmt = oRoot.con.prepareStatement(strSql);
oPrepStmt.setString(2,strProviderType);
oPrepStmt.setInt(1,oRoot.getTrUserId());
preparedstatement 未关闭的第一个实例是否会导致资源泄漏?
【问题讨论】:
你为什么要这样?为什么不先构造完整的查询字符串,然后准备语句? 如您所见,我需要动态创建查询。 "preparedstatement 的未关闭的第一个实例是否会导致资源泄漏" - 是的(尽管它在一定程度上取决于 DBMS 和 JDBC 驱动程序)。 你能告诉我更多关于这个的细节吗?此外,您能建议编写此类代码的最佳方法吗? 可以先确定需要的sql,准备好语句,再确定是否需要设置参数。多次准备一条语句的开销高于使用两条 if 语句而不是一条。 【参考方案1】:JDBC 语句实现 AutoCloseable
,因此表明在不再需要时应显式关闭。
可能持有资源的对象(例如文件或套接字句柄) 直到关闭。 AutoCloseable 对象的 close() 方法是 退出 try-with-resources 块时自动调用 该对象已在资源规范标头中声明。 这种构造保证了及时释放,避免了资源枯竭 否则可能发生的异常和错误。
所以按照 Javadoc 的建议,使用 try-with-resources 语句:
try (PreparedStatement pstmt = oRoot.con.prepareStatement(strSql))
... run sql commands ...
在您的示例中,您创建了一个语句并在某些情况下将其丢弃。最好避免这种情况并写成这样:
boolean checkUserType = strProviderType.length();
try (PreparedStatement pstmt = oRoot.con.prepareStatement(checkUserType ? strSql : strSql + " and users.usertype IN (?)")
oPrepStmt.setInt(1,oRoot.getTrUserId());
if (checkUserType)
oPrepStmt.setString(2,strProviderType);
...
【讨论】:
【参考方案2】:当你完成一个语句时,你应该总是关闭它。在某些数据库/JDBC 驱动程序中,语句还具有服务器端句柄。不关闭语句将使该句柄在服务器上保持打开状态,从而导致不必要的资源消耗(主要是内存,但它可能会锁定某些元数据对象)。
除此之外,在驱动程序端不关闭语句还可能有额外的资源消耗(内存、连接事件的侦听器等)。因此建议尽快关闭。
驱动程序最终可能会通过终结器或在您关闭连接时解除分配,但依赖它并不是一个好主意(例如,连接池中的连接并不总是正确关闭语句时返回到池中等)。
现在关于您的具体问题,您应该将代码修改为:
if (strProviderType.length() > 0)
strSql += " and users.usertype IN (?)";
try (PreparedStatement oPrepStmt = oRoot.con.prepareStatement(strSql))
oPrepStmt.setInt(1,oRoot.getTrUserId());
if (strProviderType.length() > 0)
oPrepStmt.setString(2, strProviderType);
oPrepStmt.execute(); // or executeQuery or executeUpdate
我还包含了一个 try-with-resources 以确保语句尽快关闭。
顺便说一句,您对IN(?)
的使用可能不会在大多数(所有?)数据库上像这样工作。见PreparedStatement IN clause alternatives?
【讨论】:
以上是关于创建preparedstatement的多个实例的主要内容,如果未能解决你的问题,请参考以下文章
Statement与PreparedStatement的区别
PreparedStatement 更新显示错误 ORA-00927 缺少等号