Java中处理JDBC空指针与异常的核心是提前拦截null、规范资源生命周期、精准定位源头:连接判空抛异常、结果用Optional或判空处理、资源用try-with-resources、日志带上下文。

Java 中处理 JDBC 查询中的空指针与异常,核心在于提前拦截 null、规范资源生命周期、精准定位异常源头。不是等报错再补救,而是从连接初始化、SQL 执行、结果处理到资源释放,每一步都设防。
连接对象为空:先检查,再使用
JDBC 查询最常见空指针发生在 conn.createStatement() 或 conn.prepareStatement() 时——因为 conn 本身是 null。这通常源于构造函数中数据库连接失败,但只打印堆栈、未中断流程或抛出异常,导致后续方法仍用无效连接。
- 在
query()或update()方法开头加判空:if (conn == null) throw new IllegalStateException("数据库连接未建立"); - 构造函数中不捕获异常后静默吞掉,改用
throws SQLException或主动抛运行时异常:if (conn == null) throw new RuntimeException("无法获取数据库连接,请检查驱动、URL、账号密码及服务状态"); - 确保
jdbc.properties放在src/main/resources下,并用getClassLoader().getResourceAsStream("jdbc.properties")加载,避免因类加载器差异导致流为null
查询结果为空:别直接调用方法
ResultSet rs = stmt.executeQuery(sql) 可能返回空结果集(rs.next() 返回 false),但更危险的是业务对象本身为 null:比如 BeanHandler<User> 查不到数据时返回 null,若直接 user.getName() 就崩。
- 对查询结果做非空判断:
User user = queryRunner.query(..., new BeanHandler<>(User.class)); if (user != null) { ... } - 用
BeanListHandler替代单对象处理器,即使无数据也返回空List,避免null值传播 - 远程调用或 DAO 层返回值,统一包装成
Optional<T>(Java 8+):return Optional.ofNullable(user);,上层用ifPresent或orElse处理
资源未关闭引发的连锁空指针
未正确关闭 ResultSet、Statement、Connection,可能造成连接池耗尽、下一次 getConnection() 返回 null,进而引发新空指针;此外,手动 close 时若某对象已为 null(如 rs 在 executeQuery 报错后未创建),直接 rs.close() 又会触发二次空指针。
立即学习“Java免费学习笔记(深入)”;
- 一律使用 try-with-resources:
try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { ... } - 若必须手动关闭,每个
close()前加判空:if (rs != null) try { rs.close(); } catch (SQLException e) { ... } - 不要在
finally块里写conn.close()而不判空——连接可能根本没拿到就抛异常了
异常信息要具体,别只 printStackTrace
看到 NullPointerException at DBConnection.java:41 并不能立刻知道是 conn、stmt 还是 rs 为空。原始日志缺乏上下文,排查低效。
- 在关键位置打带变量值的日志:
log.debug("执行查询前 conn = {}, sql = {}", conn, sql); - 捕获异常时包装更明确的信息:
throw new SQLException("查询失败,SQL=[" + sql + "],连接对象为null", e); - 使用
Objects.requireNonNull(conn, "数据库连接不可为空")让空值在最早入口处暴露,错误提示直指根源


















