【问题标题】:JDBC Exception java.lang.NoSuchMethodException: com.mysql.cj.jdbc.ClientPreparedStatement.close()JDBC 异常 java.lang.NoSuchMethodException: com.mysql.cj.jdbc.ClientPreparedStatement.close()
【发布时间】:2021-11-17 08:41:55
【问题描述】:

我用reflect来关闭资源,就像这样

public static void closeResource(Object ... resources) throws Exception {
    String methodName = "close";
    for (Object obj : resources){
        System.out.println(obj);
        Method m = obj.getClass().getDeclaredMethod(methodName);
        m.setAccessible(true);
        m.invoke(obj);
    }
}

但是当我用这个方法关闭PreparedStatement的时候,出现了一个Exception,就像这样

JDBCUtils.closeResource(resultSet, connection, preparedStatement);

异常如下

java.lang.NoSuchMethodException: com.mysql.cj.jdbc.ClientPreparedStatement.close()
    at java.base/java.lang.Class.getDeclaredMethod(Class.java:2613)
    at JDBC.Utils.JDBCUtils.closeResource(JDBCUtils.java:45)
    at JDBC.Query.jobsQueryTest.query(jobsQueryTest.java:63)
    at JDBC.Query.jobsQueryTest.main(jobsQueryTest.java:22)

前两个资源已经关闭成功,但最后一个失败了。

我尝试打印 PreparedStatement(java.sql.PreparedStatement) 的对象,但输出是 com.mysql.cj.jdbc.ClientPreparedStatement

我感到很困惑。

【问题讨论】:

  • 你为什么要使用这个,而不仅仅是使用 try-with-resources?另外,考虑使用AutoCloseable 而不是Object 和反射。
  • 关闭连接也可能关闭语句。此外,ClientPreparedStatement 类上没有 close() 方法。
  • 无论如何,您可能需要使用getMethod,因为getDeclaredMethod 只返回在类本身中声明的方法,而不是在超类或超接口中声明和实现的方法。
  • ClientPreparedStatement和PreparedStatement是什么关系
  • com.mysql.cj.jdbc.ClientPreparedStatementjava.sql.PreparedStatement 的实现。但是,它没有声明close(),因为它已经在其父类com.mysql.cj.jdbc.StatementImpl 中实现了。但我再次重申,你不应该使用 JDBCUtils.closeResource 这样的东西。请改用 try-with-resources。

标签: java jdbc


【解决方案1】:

替代方案,不要使用反射,而是如果您知道要关闭的资源类型,则可以将它们强制转换为允许close() 的各自接口:

ClientPreparedStatement 确实是implements Statement,所以这应该可以工作:

public static void closeResource(Object... resources) throws SQLException {
    for (Object obj : resources) {
        if (obj instanceof Statement) {
            Statement statement = (Statement) obj;
            statement.close();
        }
        if (obj instanceof Connection) {
            Connection connection = (Connection) obj;
            connection.close();
        } else {
            //Log to see if you missed any resource;
        }
    }
}

按照 Mark 的建议,请将您的代码重构为 Try-with-Resources。这样Java就为你关闭了一切,你不用担心资源泄露。

    String sql = "SELECT ...";
    String connectionURL = "";

    try (Connection con = DriverManager.getConnection(connectionURL);
         PreparedStatement ps = con.prepareStatement(sql)) {

        ps.setString(1, "12345");

        try (ResultSet rs = ps.executeQuery()) {

        }
    } catch (SQLException e) {
        //Log e
    }

【讨论】:

  • 在第一个解决方案中,您还可以检查obj instanceof AutoCloseable,因为java.sql.Connectionjava.sql.Statement都对其进行了扩展。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 2013-06-13
  • 2019-12-26
  • 2011-06-12
  • 1970-01-01
相关资源
最近更新 更多