java.sql.SQLException异常原因排查与解决

 更新时间:2025年09月29日 09:28:04   作者:网罗开发  
在日常开发中,大家应该或多或少都遇到SQL 在本地跑得好好的,一放到服务里执行就报 java.sql.SQLException,本文将结合一个小 Demo,带大家看一下 SQLException 的常见原因,以及如何一步步排查

前言

在日常开发中,大家应该或多或少都遇到过这种情况:SQL 在本地跑得好好的,一放到服务里执行就报 java.sql.SQLException。很多同学看到这个异常时,第一反应就是“是不是数据库挂了?”。其实绝大多数情况跟数据库无关,而是 SQL 拼接、参数绑定或者日志缺失导致的。

这篇文章我结合一个小 Demo,带大家看一下 SQLException 的常见原因,以及如何一步步排查。

场景描述:常见的 SQLException 问题

假设我们有一张 users 表,结构很简单:

CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    age INT
);

在 Java 项目里写了一个最普通的查询:

String sql = "SELECT * FROM users WHERE username = ? AND age = ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, "zhangfei");
ps.setInt(2, 18);

ResultSet rs = ps.executeQuery();

看似没问题,但在真实项目里,很容易因为下面几个问题报 SQLException

  • SQL 拼接错误:比如忘了 AND,或者参数占位符数量不对。
  • 参数绑定异常:明明是数字,结果 setString();或者顺序错了。
  • SQL 没有打印日志:导致无法复现真实执行的 SQL。

排查思路:怎么快速锁定问题?

遇到 SQLException 时,不要慌,通常从以下几个角度来排查:

1.打印完整 SQL

很多时候,你以为你执行的是 SELECT * FROM users WHERE username = 'zhangfei',实际上可能变成了 SELECT * FROM users WHERE username = 'null'

2.检查参数绑定

确认每个 ? 是否都被正确赋值,并且类型匹配。

3.用日志记录 SQL

不仅要打印原始 SQL,还要把 参数替换后的 SQL 打出来,方便直接拿去数据库执行。

Demo:带日志的 SQL 执行封装

我们可以写一个简单的工具方法来封装 SQL 执行和日志打印。这样每次执行 SQL 时,都能清晰看到完整的 SQL。

import java.sql.*;
import java.util.Arrays;

public class JdbcHelper {

    public static void executeQuery(Connection conn, String sql, Object... params) {
        try (PreparedStatement ps = conn.prepareStatement(sql)) {

            // 参数绑定
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }

            // 打印完整 SQL
            System.out.println("Executing SQL: " + buildFullSql(sql, params));

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    System.out.println("User: " + rs.getString("username") + ", Age: " + rs.getInt("age"));
                }
            }

        } catch (SQLException e) {
            System.err.println("SQL 执行异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 将参数替换到 SQL 中(简易版)
    private static String buildFullSql(String sql, Object... params) {
        String fullSql = sql;
        for (Object param : params) {
            String value = (param instanceof String) ? "'" + param + "'" : String.valueOf(param);
            fullSql = fullSql.replaceFirst("\\?", value);
        }
        return fullSql;
    }

    // Demo 入口
    public static void main(String[] args) throws Exception {
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/testdb", "root", "password");

        executeQuery(conn, "SELECT * FROM users WHERE username = ? AND age = ?", "zhangfei", 18);
    }
}

运行效果:

Executing SQL: SELECT * FROM users WHERE username = 'zhangfei' AND age = 18
User: zhangfei, Age: 18

一旦 SQL 写错,比如参数缺失,就能立刻在日志里看到:

Executing SQL: SELECT * FROM users WHERE username = 'zhangfei' AND age = null
SQL 执行异常: Unknown column 'null' in 'where clause'

是不是就一目了然了?

结合实际开发的应用

在真实的业务开发中,SQLException 的定位通常会踩到几个坑:

  • 多服务场景:调用链太长,不知道 SQL 是在哪个微服务里执行的。
  • ORM 框架二次封装:比如 MyBatis,把 SQL 隐藏在 XML 里,导致排查困难。
  • 日志打印不全:只打印了原始 SQL,没有参数,运维无法复现。

因此,建议大家在项目里加一个 SQL 拦截器,不论是 MyBatis 的 Interceptor,还是 JPA 的日志配置,都要确保能拿到 完整 SQL

总结

java.sql.SQLException 本质上不是“数据库坏了”,而是代码逻辑和 SQL 执行之间的沟通问题。核心思路就是:

  • 先把完整 SQL 打印出来
  • 确认参数绑定是否正确
  • 保证日志可复现

这样基本上 90% 的 SQL 问题都能快速解决。

到此这篇关于java.sql.SQLException异常原因排查与解决的文章就介绍到这了,更多相关java.sql.SQLException解决内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 8中日期和时间的处理方法

    Java 8中日期和时间的处理方法

    Java 8新增了LocalDate和LocalTime接口,接下来通过本文给大家介绍Java 8中日期和时间的处理方法,非常不错,感兴趣的朋友一起看下吧
    2016-08-08
  • Java 8 新特性终极版指南详解

    Java 8 新特性终极版指南详解

    Java 8已经公布有一段时间了,种种迹象表明Java 8是一个有重大改变的发行版。本文给大家介绍Java 8 新特性终极版指南详解,需要的朋友参考下
    2016-03-03
  • 解决SpringBoot2.1.0+RocketMQ版本冲突问题

    解决SpringBoot2.1.0+RocketMQ版本冲突问题

    这篇文章主要介绍了解决SpringBoot2.1.0+RocketMQ版本冲突问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 详解springSecurity之java配置篇

    详解springSecurity之java配置篇

    这篇文章主要介绍了详解springSecurity之java配置篇,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 详解SpringBoot文件上传下载和多文件上传(图文)

    详解SpringBoot文件上传下载和多文件上传(图文)

    本篇文章主要介绍了详解SpringBoot文件上传下载和多文件上传(图文),具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02
  • Java聊天室之使用Socket实现传递图片

    Java聊天室之使用Socket实现传递图片

    这篇文章主要为大家详细介绍了Java简易聊天室之使用Socket实现传递图片功能,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以了解一下
    2022-10-10
  • Java开发框架spring实现自定义缓存标签

    Java开发框架spring实现自定义缓存标签

    这篇文章主要介绍了Java开发框架spring实现自定义缓存标签的详细代码,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • Spring Boot 中集成 Lombok 和 MapStruct最佳实践指南

    Spring Boot 中集成 Lombok 和 MapStruct最

    文章详解SpringBoot项目中Lombok与MapStruct整合实践,涵盖版本兼容、IDE配置、代码分层、映射配置、测试验证及性能优化,重点解决注解冲突、依赖注入等常见问题,强调分层管理和组件扫描配置,提升开发效率与代码简洁性,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2025-08-08
  • 使用idea搭建一个spring mvc项目的图文教程

    使用idea搭建一个spring mvc项目的图文教程

    这篇文章主要介绍了使用idea直接创建一个spring mvc项目的图文教程,本文通过图文并茂的方式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • Java实现HDFS文件上传下载

    Java实现HDFS文件上传下载

    这篇文章主要为大家详细介绍了Java实现HDFS文件上传下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06

最新评论