java.sql.SQLException異常原因排查與解決
前言
在日常開發(fā)中,大家應該或多或少都遇到過這種情況:SQL 在本地跑得好好的,一放到服務里執(zhí)行就報 java.sql.SQLException。很多同學看到這個異常時,第一反應就是“是不是數(shù)據(jù)庫掛了?”。其實絕大多數(shù)情況跟數(shù)據(jù)庫無關,而是 SQL 拼接、參數(shù)綁定或者日志缺失導致的。
這篇文章我結合一個小 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,或者參數(shù)占位符數(shù)量不對。 - 參數(shù)綁定異常:明明是數(shù)字,結果 setString();或者順序錯了。
- SQL 沒有打印日志:導致無法復現(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'
是不是就一目了然了?
結合實際開發(fā)的應用
在真實的業(yè)務開發(fā)中,SQLException 的定位通常會踩到幾個坑:
- 多服務場景:調用鏈太長,不知道 SQL 是在哪個微服務里執(zhí)行的。
- ORM 框架二次封裝:比如 MyBatis,把 SQL 隱藏在 XML 里,導致排查困難。
- 日志打印不全:只打印了原始 SQL,沒有參數(shù),運維無法復現(xiàn)。
因此,建議大家在項目里加一個 SQL 攔截器,不論是 MyBatis 的 Interceptor,還是 JPA 的日志配置,都要確保能拿到 完整 SQL。
總結
java.sql.SQLException 本質上不是“數(shù)據(jù)庫壞了”,而是代碼邏輯和 SQL 執(zhí)行之間的溝通問題。核心思路就是:
- 先把完整 SQL 打印出來
- 確認參數(shù)綁定是否正確
- 保證日志可復現(xiàn)
這樣基本上 90% 的 SQL 問題都能快速解決。
到此這篇關于java.sql.SQLException異常原因排查與解決的文章就介紹到這了,更多相關java.sql.SQLException解決內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 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: 內部錯誤: Unable to construct a Datum from the specified input
相關文章
解決SpringBoot2.1.0+RocketMQ版本沖突問題
這篇文章主要介紹了解決SpringBoot2.1.0+RocketMQ版本沖突問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06
Java開發(fā)框架spring實現(xiàn)自定義緩存標簽
這篇文章主要介紹了Java開發(fā)框架spring實現(xiàn)自定義緩存標簽的詳細代碼,感興趣的小伙伴們可以參考一下2015-12-12
Spring Boot 中集成 Lombok 和 MapStruct最
文章詳解SpringBoot項目中Lombok與MapStruct整合實踐,涵蓋版本兼容、IDE配置、代碼分層、映射配置、測試驗證及性能優(yōu)化,重點解決注解沖突、依賴注入等常見問題,強調分層管理和組件掃描配置,提升開發(fā)效率與代碼簡潔性,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧2025-08-08

