java.sql.SQLException異常原因排查與解決
前言
在日常開發(fā)中,大家應(yīng)該或多或少都遇到過這種情況:SQL 在本地跑得好好的,一放到服務(wù)里執(zhí)行就報 java.sql.SQLException。很多同學(xué)看到這個異常時,第一反應(yīng)就是“是不是數(shù)據(jù)庫掛了?”。其實絕大多數(shù)情況跟數(shù)據(jù)庫無關(guān),而是 SQL 拼接、參數(shù)綁定或者日志缺失導(dǎo)致的。
這篇文章我結(jié)合一個小 Demo,帶大家看一下 SQLException 的常見原因,以及如何一步步排查。
場景描述:常見的 SQLException 問題
假設(shè)我們有一張 users 表,結(jié)構(gòu)很簡單:
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,或者參數(shù)占位符數(shù)量不對。 - 參數(shù)綁定異常:明明是數(shù)字,結(jié)果 setString();或者順序錯了。
- SQL 沒有打印日志:導(dǎo)致無法復(fù)現(xiàn)真實執(zhí)行的 SQL。
排查思路:怎么快速鎖定問題?
遇到 SQLException 時,不要慌,通常從以下幾個角度來排查:
1.打印完整 SQL
很多時候,你以為你執(zhí)行的是 SELECT * FROM users WHERE username = 'zhangfei',實際上可能變成了 SELECT * FROM users WHERE username = 'null'。
2.檢查參數(shù)綁定
確認每個 ? 是否都被正確賦值,并且類型匹配。
3.用日志記錄 SQL
不僅要打印原始 SQL,還要把 參數(shù)替換后的 SQL 打出來,方便直接拿去數(shù)據(jù)庫執(zhí)行。
Demo:帶日志的 SQL 執(zhí)行封裝
我們可以寫一個簡單的工具方法來封裝 SQL 執(zhí)行和日志打印。這樣每次執(zhí)行 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)) {
// 參數(shù)綁定
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 執(zhí)行異常: " + e.getMessage());
e.printStackTrace();
}
}
// 將參數(shù)替換到 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 寫錯,比如參數(shù)缺失,就能立刻在日志里看到:
Executing SQL: SELECT * FROM users WHERE username = 'zhangfei' AND age = null
SQL 執(zhí)行異常: Unknown column 'null' in 'where clause'
是不是就一目了然了?
結(jié)合實際開發(fā)的應(yīng)用
在真實的業(yè)務(wù)開發(fā)中,SQLException 的定位通常會踩到幾個坑:
- 多服務(wù)場景:調(diào)用鏈太長,不知道 SQL 是在哪個微服務(wù)里執(zhí)行的。
- ORM 框架二次封裝:比如 MyBatis,把 SQL 隱藏在 XML 里,導(dǎo)致排查困難。
- 日志打印不全:只打印了原始 SQL,沒有參數(shù),運維無法復(fù)現(xiàn)。
因此,建議大家在項目里加一個 SQL 攔截器,不論是 MyBatis 的 Interceptor,還是 JPA 的日志配置,都要確保能拿到 完整 SQL。
總結(jié)
java.sql.SQLException 本質(zhì)上不是“數(shù)據(jù)庫壞了”,而是代碼邏輯和 SQL 執(zhí)行之間的溝通問題。核心思路就是:
- 先把完整 SQL 打印出來
- 確認參數(shù)綁定是否正確
- 保證日志可復(fù)現(xiàn)
這樣基本上 90% 的 SQL 問題都能快速解決。
到此這篇關(guān)于java.sql.SQLException異常原因排查與解決的文章就介紹到這了,更多相關(guān)java.sql.SQLException解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- mysql字符集引起的java.sql.SQLException:Incorrect?string?value:問題
- java.sql.SQLException:?connection?holder?is?null錯誤解決辦法
- Java中java.sql.SQLException異常的正確解決方法(親測有效!)
- java報錯Cause: java.sql.SQLException問題解決
- java.sql.SQLException問題解決以及注意事項
- java.sql.SQLException: 內(nèi)部錯誤: Unable to construct a Datum from the specified input
相關(guān)文章
Idea如何配置Maven才能優(yōu)先從本地倉庫獲取依賴(親測方法有效)
對于Idea怎么配置Maven才能優(yōu)先從本地倉庫獲取依賴,網(wǎng)上說法有很多種,都不太靠譜,最終都沒有效果,最好的解決方法是通過修改maven配置文件settings.xml,本文給大家介紹的非常詳細,需要的朋友參考下吧2023-10-10
Gradle build 報錯:Received status code 400 from server
這篇文章主要介紹了Gradle build 報錯:Received status code 400 from server,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
使用Java生成永不重復(fù)的數(shù)字的實現(xiàn)方案
在現(xiàn)代應(yīng)用開發(fā)中,一個常見的需求是生成 永不重復(fù)的數(shù)字,無論是在訂單系統(tǒng)中生成唯一訂單號,還是分布式系統(tǒng)中生成唯一標識,生成不重復(fù)的數(shù)字或ID都是至關(guān)重要的,本期我們將關(guān)注 Java 生產(chǎn)永不重復(fù)的數(shù)字,通過多個角度剖析不同場景下的解決方案,需要的朋友可以參考下2025-06-06

