DriverManager 或 JNDI DataSource(推薦生產環境用連接池)。Statement(靜態 SQL)或 PreparedStatement(參數化、防注入、預編譯優化)。ResultSet,更新返回影響行數。ResultSet → Statement → Connection,建議用 try-with-resources 自動關閉。// 滾動且只讀
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
rs.absolute(9000); // 直接跳轉第 9000 行
// 可更新
PreparedStatement ps = conn.prepareStatement(sql,
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = ps.executeQuery();
rs.updateString("name", "NewName");
rs.updateRow(); // 寫回數據庫
TYPE_SCROLL_INSENSITIVE:結果集開啟後不感知底層數據變化;SENSITIVE 則可見實時變更(性能較差)。
Statement 批量:多條不同 SQL 一次提交:
Statement stmt = conn.createStatement();
stmt.addBatch("INSERT INTO log VALUES (1, 'a')");
stmt.addBatch("UPDATE user SET cnt=cnt+1 WHERE id=1");
stmt.addBatch("DELETE FROM temp WHERE expired=1");
int[] counts = stmt.executeBatch(); // 返回各條影響行數
PreparedStatement 批量:同一 SQL,不同參數集批量執行:
PreparedStatement ps = conn.prepareStatement("INSERT INTO user(id,name) VALUES(?,?)");
for (User u : users) {
ps.setInt(1, u.getId());
ps.setString(2, u.getName());
ps.addBatch();
}
int[] counts = ps.executeBatch();
批量操作大幅減少網絡往返,插入萬條數據可從分鐘級降至秒級。
conn.setAutoCommit(false); // 關閉自動提交
try {
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO orders ..."); stmt.close();
stmt = conn.createStatement();
stmt.executeUpdate("UPDATE inventory SET qty=qty-1 ..."); stmt.close();
conn.commit(); // 全部成功才提交
} catch (SQLException e) {
conn.rollback(); // 任一失敗全回滾
throw e;
} finally {
conn.setAutoCommit(true); // 恢復默認
}
核心原則:同一事務內每條 SQL 用完 Statement 即關閉,避免游標泄漏;異常時必須回滾;連接池環境下 close() 實際是歸還連接,不影響事務邊界(由連接池管理)。
setFetchSize() 減少內存壓力。