【问题标题】:Creating multiple instances of preparedstatement创建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 语句而不是一条。

标签: java database jdbc prepared-statement


【解决方案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?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-17
      • 1970-01-01
      • 2017-01-30
      • 1970-01-01
      • 2017-03-30
      • 2018-07-11
      • 2017-11-15
      • 2020-07-08
      相关资源
      最近更新 更多