Class.forName("com.mysql.cj.jdbc.Driver") (JDBC 4.0+ 可省略)DriverManager.getConnection(url, user, pass) 或 JNDI DataSourceexecuteQuery (查詢) / executeUpdate (增刪改)ResultSetResultSet → Statement → Connection(逆序,try-with-resources 最佳)String url = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC";
String user = "root", pass = "123456";
try (Connection conn = DriverManager.getConnection(url, user, pass)) {
// 使用連線
}
// web.xml / context.xml 配置資料源
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
try (Connection conn = ds.getConnection()) {
// 連線池管理、事務整合更優
}
| 特性 | Statement | PreparedStatement |
|---|---|---|
| SQL 注入防護 | 無,需手動轉義 | 參數化查詢,原生防注入 |
| 效能 | 每次編譯 | 預編譯,批次執行極快 |
| 適用場景 | 靜態 SQL、DDL | 業務 CRUD、動態條件、批次操作 |
原則:業務代碼**永遠使用 PreparedStatement**。
// 建立可捲動、可更新 ResultSet
try (Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {
rs.absolute(5); // 直接跳第 5 行
rs.previous(); // 上一行
rs.updateString("name", "新名稱");
rs.updateRow(); // 寫回資料庫
rs.insertRow(); // 插入新行
rs.deleteRow(); // 刪除當前行
}
注意:需資料庫驅動支援,主鍵無 NULL,且查詢需包含主鍵欄位。
try (Statement stmt = conn.createStatement()) {
stmt.addBatch("INSERT INTO log VALUES (1, 'msg1')");
stmt.addBatch("UPDATE user SET cnt=cnt+1 WHERE id=2");
stmt.addBatch("DELETE FROM temp WHERE id=3");
int[] counts = stmt.executeBatch(); // 每條影響行數
}
String sql = "INSERT INTO user(name, email) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
for (User u : userList) {
ps.setString(1, u.getName());
ps.setString(2, u.getEmail());
ps.addBatch();
// 每 1000 條執行一次,防 OOM
if (++count % 1000 == 0) ps.executeBatch();
}
ps.executeBatch(); // 剩餘
}
關鍵優化:MySQL 需 URL 附加 rewriteBatchedStatements=true 才能真正批次執行,否則退化為單條循環。
Connection conn = null;
try {
conn = ds.getConnection();
conn.setAutoCommit(false); // 開啟事務
try (PreparedStatement ps1 = conn.prepareStatement(sql1);
PreparedStatement ps2 = conn.prepareStatement(sql2)) {
// 業務邏輯
ps1.executeUpdate();
ps2.executeUpdate();
}
conn.commit(); // 提交
} catch (Exception e) {
if (conn != null) conn.rollback(); // 回滾
throw e;
} finally {
if (conn != null) {
conn.setAutoCommit(true); // 恢復預設
conn.close();
}
}
最佳實踐:使用 Spring @Transactional 或 JTA 容器事務,避免手動管理錯誤。
// Java 7+ 標準寫法
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
// 邏輯
} // 自動按逆序關閉 rs → ps → conn
JDBC 雖屬基礎,但「連線池選擇、PreparedStatement 堅持、批次重寫優化、事務邊界清晰、資源自動關閉」五大鐵律,是區分新手與資深工程師的分水嶺。掌握這些,再配合 MyBatis/JdbcTemplate 等框架,才能寫出高性能、穩健的數據訪問層。