JEE Servlet SQLException处理实践咨询:当前写法是否规范及优化方案
问题解答
关于异常捕获的理解纠正
你的理解有误:getAllGrades()方法里的catch (Exception e)已经能捕获connection()抛出的所有异常。因为Exception是所有非运行时异常(包括connection()可能抛出的ClassNotFoundException、SQLException)的父类,只要connection()抛出的异常属于Exception的子类,都会被这个catch块捕获。
当前代码的异常处理并非最佳实践,存在多个问题
- 静态资源变量线程不安全:
con、stmt、rs都是静态成员变量,多线程环境下多个调用会互相覆盖资源,导致连接泄漏、结果集混乱等问题。 - 资源未正确关闭:仅在正常流程关闭了
Connection,如果rs.next()、stmt.executeQuery()等步骤抛出异常,con.close()不会执行;同时PreparedStatement和ResultSet完全没关闭,会造成数据库资源泄漏。 - 异常处理过于粗糙:仅打印堆栈轨迹,上层调用者无法感知异常发生,且返回
null极易引发空指针异常。 - 异常声明过于宽泛:
connection()方法直接抛出Exception,调用者无法明确知道可能发生哪些具体异常,不利于针对性处理。
更优的替代方案
核心优化点
- 用局部变量替代静态资源变量,每个方法调用独立持有资源,避免线程冲突。
- 使用try-with-resources语法(Java 7+),自动关闭
Connection、PreparedStatement、ResultSet,确保资源无论是否异常都会被释放。 - 细化异常处理:要么抛出具体的受检异常让上层业务逻辑处理,要么封装为自定义运行时异常,不要静默吞掉异常后返回
null。 - 明确异常声明:
connection()方法抛出具体的ClassNotFoundException和SQLException,而非笼统的Exception。 - 避免硬编码数据库配置,可通过配置文件读取(示例中暂保留硬编码,实际项目建议优化)。
优化后代码示例
package DAO; import java.sql.*; import java.util.ArrayList; import java.util.List; public class StudentDAO { // 获取连接,抛出具体异常 private static Connection getConnection() throws ClassNotFoundException, SQLException { Class.forName("oracle.jdbc.driver.OracleDriver"); return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "xxx", "yyy"); } public static List<String> getAllGrades() throws SQLException, ClassNotFoundException { // 使用try-with-resources自动关闭资源 try (Connection con = getConnection(); PreparedStatement stmt = con.prepareStatement("SELECT DISTINCT grade from student"); ResultSet rs = stmt.executeQuery()) { List<String> grades = new ArrayList<>(); while (rs.next()) { grades.add(rs.getString(1)); } return grades; } // 若需封装异常,可取消下面注释,抛出自定义运行时异常 // catch (SQLException | ClassNotFoundException e) { // throw new DAOException("获取成绩列表失败", e); // } } // 自定义运行时异常示例(可选) static class DAOException extends RuntimeException { public DAOException(String message, Throwable cause) { super(message, cause); } } }
补充说明
- 如果业务层不希望处理受检异常,可以将捕获的
SQLException和ClassNotFoundException封装为自定义运行时异常(如示例中的DAOException),上层调用时无需显式捕获,更符合业务逻辑的异常处理流程。 - 实际项目中,建议使用数据库连接池(如HikariCP)替代直接通过
DriverManager获取连接,提升性能和资源管理效率。
内容的提问来源于stack exchange,提问作者Strannngahhhh
相关产品推荐
相关产品推荐

