JDBC(Java Database Connectivity)是 Java 操作關係型資料庫的標準 API。本文從驅動載入、連接建立、中文亂碼處理、CRUD 操作、預處理語句到事務控制,提供完整的 JSP + MySQL 實戰指南。
Class.forName("com.mysql.jdbc.Driver")DriverManager.getConnection(url, user, pwd)Statement / PreparedStatement 執行查詢或更新$JAVA_HOME/jre/lib/ext/$TOMCAT_HOME/lib/(推薦,隔離專案依賴)// 三參數形式
String url = "jdbc:mysql://192.168.1.100:3306/testdb";
String user = "root";
String pwd = "123456";
Connection conn = DriverManager.getConnection(url, user, pwd);
// 單參數形式(含參數)
String url = "jdbc:mysql://192.168.1.100:3306/testdb?user=root&password=123456&characterEncoding=utf8";
Connection conn = DriverManager.getConnection(url);
| 層面 | 配置方式 |
|---|---|
| 資料庫/表 | CREATE DATABASE testdb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; |
| 連接 URL | 添加 characterEncoding=utf8(或 utf8mb4) |
| JSP 頁面 | <%@ page contentType="text/html;charset=utf-8" %> |
| Tomcat | server.xml Connector 添加 URIEncoding="UTF-8" |
Statement stmt = conn.createStatement();
// 查詢
ResultSet rs = stmt.executeQuery("SELECT id, name FROM users");
while (rs.next()) {
System.out.println(rs.getInt("id") + " - " + rs.getString("name"));
}
// 新增/修改/刪除(返回影響行數)
int rows = stmt.executeUpdate("INSERT INTO users(name) VALUES('Tom')");
rows = stmt.executeUpdate("UPDATE users SET name='Jerry' WHERE id=1");
rows = stmt.executeUpdate("DELETE FROM users WHERE id=2");
// 獲取可滾動、可更新的結果集
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, // 游標可上下移動,不感知資料庫變更
ResultSet.CONCUR_UPDATABLE // 允許透過結果集更新資料庫
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
// 常用導航方法
rs.first(); rs.last(); rs.beforeFirst(); rs.afterLast();
rs.absolute(5); rs.relative(-2); rs.previous();
int rowNum = rs.getRow(); // 當前行號(從 1 開始)
// 更新第 4 行 name 欄位
rs.absolute(4);
rs.updateString("name", "Jason Statham");
rs.updateRow(); // 同步回資料庫
// 插入新行
rs.moveToInsertRow();
rs.updateString("name", "New User");
rs.updateInt("age", 25);
rs.insertRow(); // 寫入資料庫
rs.moveToCurrentRow(); // 返回原游標位置
優勢:SQL 預編譯、防止 SQL 注入、批次執行效能高、可讀性好。
// 使用佔位符 ?
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE age > ? AND status = ?"
);
ps.setInt(1, 18);
ps.setString(2, "active");
ResultSet rs = ps.executeQuery();
// 批次插入範例
conn.setAutoCommit(false);
PreparedStatement batchPs = conn.prepareStatement("INSERT INTO logs(msg) VALUES(?)");
for (int i = 0; i < 1000; i++) {
batchPs.setString(1, "Log entry " + i);
batchPs.addBatch();
}
batchPs.executeBatch();
conn.commit();
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, pwd);
conn.setAutoCommit(false); // 關閉自動提交,開啟事務
// 業務邏輯:轉帳扣款 + 存入
PreparedStatement ps1 = conn.prepareStatement("UPDATE account SET balance=balance-100 WHERE id=1");
PreparedStatement ps2 = conn.prepareStatement("UPDATE account SET balance=balance+100 WHERE id=2");
ps1.executeUpdate();
ps2.executeUpdate();
conn.commit(); // 全部成功提交
} catch (SQLException e) {
if (conn != null) conn.rollback(); // 任一失敗回滾
e.printStackTrace();
} finally {
if (conn != null) {
try { conn.setAutoCommit(true); conn.close(); } catch (SQLException ignore) {}
}
}
| 方法 | 說明 |
|---|---|
setAutoCommit(false) | 關閉自動提交,手動控制事務邊界 |
commit() | 提交事務,持久化所有操作 |
rollback() | 回滾事務,撤銷未提交的變更 |
生產建議:實際專案請使用連接池(HikariCP/Druid)與 Spring 宣告式事務(@Transactional),避免手動管理連接與事務導致資源洩漏。