反射关闭PreparedStatement报ClientPreparedStatement.close()不存在异常如何解决
异常原因
Class.getDeclaredMethod()只能获取当前类自身声明的方法,无法获取从父类、接口继承来的方法。- 你使用的MySQL驱动中
com.mysql.cj.jdbc.ClientPreparedStatement的close()方法并非该类自身实现,而是继承自上层父类或java.sql.PreparedStatement接口,因此getDeclaredMethod()无法匹配到对应方法,抛出NoSuchMethodException。 - 前两个资源关闭成功,是因为对应的ResultSet、Connection实现类刚好自身重写了
close()方法,所以能被该方法匹配到。
解决方案
方案1:优先使用Java原生try-with-resources(最推荐)
Java 7及以上版本提供的try-with-resources语法可以自动关闭所有实现AutoCloseable接口的资源,无需手写关闭工具类,自动按逆序关闭资源,避免遗漏和异常:
try ( Connection connection = DriverManager.getConnection(dbUrl, username, password); PreparedStatement preparedStatement = connection.prepareStatement(querySql); ResultSet resultSet = preparedStatement.executeQuery() ) { // 业务逻辑代码 } catch (SQLException e) { // 异常处理逻辑 e.printStackTrace(); }
方案2:修改反射工具类的方法获取逻辑
如果需要保留自定义关闭工具类,把getDeclaredMethod替换为getMethod即可,getMethod可以获取类的所有public方法,包括继承来的:
public static void closeResource(Object ... resources) { String methodName = "close"; for (Object obj : resources){ // 先判空避免空指针 if (obj == null) { continue; } try { Method m = obj.getClass().getMethod(methodName); // close方法本身是public,不需要setAccessible m.invoke(obj); } catch (Exception e) { // 单个资源关闭失败不要抛出,避免影响其他资源关闭,可自行替换为日志打印 e.printStackTrace(); } } }
方案3:改用AutoCloseable强转实现(比反射更安全高效)
JDBC所有资源都实现了AutoCloseable接口,直接基于接口实现关闭逻辑,无需反射,性能更高逻辑更稳定:
public static void closeResource(AutoCloseable... resources) { for (AutoCloseable res : resources) { if (res == null) { continue; } try { res.close(); } catch (Exception e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者丨Vb丨
相关产品推荐
相关产品推荐

