Java JDBC 資料庫操作
JDBC (Java Database Connectivity) 是 Java 連接資料庫的標準 API,可以操作各種關聯式資料庫。
引入驅動程式
<!-- Maven - MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Maven - PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
</dependency>
建立連線
import java.sql.*;
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String password = "password";
// 方法 1:DriverManager
try (Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("連線成功!");
}
// 方法 2:使用 Properties
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", password);
props.setProperty("useSSL", "false");
try (Connection conn = DriverManager.getConnection(url, props)) {
// ...
}
查詢資料 (SELECT)
String sql = "SELECT id, name, email FROM users WHERE age > ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, 18); // 設定參數
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
System.out.println(id + ": " + name + " - " + email);
}
}
}
新增資料 (INSERT)
String sql = "INSERT INTO users (name, email, age) VALUES (?, ?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setString(1, "Alice");
pstmt.setString(2, "alice@example.com");
pstmt.setInt(3, 25);
int rows = pstmt.executeUpdate();
System.out.println("新增 " + rows + " 筆");
// 取得自動產生的 ID
try (ResultSet rs = pstmt.getGeneratedKeys()) {
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("新 ID: " + id);
}
}
}
更新資料 (UPDATE)
String sql = "UPDATE users SET email = ? WHERE id = ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "newemail@example.com");
pstmt.setInt(2, 1);
int rows = pstmt.executeUpdate();
System.out.println("更新 " + rows + " 筆");
}
刪除資料 (DELETE)
String sql = "DELETE FROM users WHERE id = ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, 1);
int rows = pstmt.executeUpdate();
System.out.println("刪除 " + rows + " 筆");
}
交易處理
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
conn.setAutoCommit(false); // 關閉自動提交
// 執行多個操作
try (PreparedStatement pstmt1 = conn.prepareStatement(
"UPDATE accounts SET balance = balance - ? WHERE id = ?")) {
pstmt1.setDouble(1, 100);
pstmt1.setInt(2, 1);
pstmt1.executeUpdate();
}
try (PreparedStatement pstmt2 = conn.prepareStatement(
"UPDATE accounts SET balance = balance + ? WHERE id = ?")) {
pstmt2.setDouble(1, 100);
pstmt2.setInt(2, 2);
pstmt2.executeUpdate();
}
conn.commit(); // 提交交易
System.out.println("轉帳成功");
} catch (SQLException e) {
if (conn != null) {
try {
conn.rollback(); // 回滾
System.out.println("交易已回滾");
} catch (SQLException ex) {
ex.printStackTrace();
}
}
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
批次處理
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
conn.setAutoCommit(false);
for (int i = 0; i < 1000; i++) {
pstmt.setString(1, "User" + i);
pstmt.setString(2, "user" + i + "@example.com");
pstmt.addBatch();
if (i % 100 == 0) {
pstmt.executeBatch(); // 每 100 筆執行一次
}
}
pstmt.executeBatch(); // 執行剩餘的
conn.commit();
}
連線池(使用 HikariCP)
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10);
config.setMinimumIdle(2);
HikariDataSource dataSource = new HikariDataSource(config);
// 取得連線
try (Connection conn = dataSource.getConnection()) {
// 使用連線...
}
// 關閉連線池
dataSource.close();
DAO 模式
public class UserDao {
private final DataSource dataSource;
public UserDao(DataSource dataSource) {
this.dataSource = dataSource;
}
public Optional<User> findById(int id) throws SQLException {
String sql = "SELECT * FROM users WHERE id = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return Optional.of(mapToUser(rs));
}
}
}
return Optional.empty();
}
private User mapToUser(ResultSet rs) throws SQLException {
return new User(
rs.getInt("id"),
rs.getString("name"),
rs.getString("email")
);
}
}
重點整理
- 使用
PreparedStatement防止 SQL 注入 - 使用 try-with-resources 自動關閉資源
- 交易需要手動關閉
autoCommit並處理commit/rollback - 批次處理提升大量資料操作效能
- 生產環境必須使用連線池
- 考慮使用 ORM 框架(如 Hibernate、MyBatis)簡化操作