採用三層結構分離關注點:
jdbc.driver_class=oracle.jdbc.driver.OracleDriver
jdbc.connection.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.connection.username=scott
jdbc.connection.password=tiger
package com.book.util;
import java.io.*;
import java.util.Properties;
public class ConfigManager {
private static ConfigManager instance;
private static Properties props = new Properties();
private ConfigManager() {
String file = "database.properties";
try (InputStream is = getClass().getClassLoader().getResourceAsStream(file)) {
if (is == null) throw new RuntimeException("找不到 " + file);
props.load(is);
} catch (IOException e) {
throw new RuntimeException("載入設定檔失敗", e);
}
}
public static synchronized ConfigManager getInstance() {
if (instance == null) instance = new ConfigManager();
return instance;
}
public String getString(String key) {
return props.getProperty(key);
}
}
package com.book.dao;
import java.sql.*;
import com.book.util.ConfigManager;
public class BaseDao {
protected Connection conn;
protected PreparedStatement ps;
protected ResultSet rs;
// 取得連線
protected boolean openConnection() {
try {
String driver = ConfigManager.getInstance().getString("jdbc.driver_class");
String url = ConfigManager.getInstance().getString("jdbc.connection.url");
String user = ConfigManager.getInstance().getString("jdbc.connection.username");
String pwd = ConfigManager.getInstance().getString("jdbc.connection.password");
Class.forName(driver);
conn = DriverManager.getConnection(url, user, pwd);
return true;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
return false;
}
}
// 增刪改
protected int executeUpdate(String sql, Object... params) {
int rows = 0;
if (!openConnection()) return 0;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
rows = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
closeAll();
}
return rows;
}
// 查詢
protected ResultSet executeQuery(String sql, Object... params) {
if (!openConnection()) return null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
rs = ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
// 注意:呼叫端必須自行關閉 rs、ps、conn
return rs;
}
// 關閉資源(遵循建立順序逆序關閉)
protected void closeAll() {
try { if (rs != null) rs.close(); } catch (SQLException ignored) {}
try { if (ps != null) ps.close(); } catch (SQLException ignored) {}
try { if (conn != null) conn.close(); } catch (SQLException ignored) {}
}
}
public class BookDao extends BaseDao {
public int addBook(String name, double price) {
String sql = "INSERT INTO books(name, price) VALUES(?, ?)";
return executeUpdate(sql, name, price);
}
public List<Book> queryAll() {
String sql = "SELECT id, name, price FROM books";
List<Book> list = new ArrayList<>();
try (ResultSet rs = executeQuery(sql)) {
while (rs != null && rs.next()) {
Book b = new Book();
b.setId(rs.getInt("id"));
b.setName(rs.getString("name"));
b.setPrice(rs.getDouble("price"));
list.add(b);
}
} catch (SQLException e) { e.printStackTrace(); }
return list;
}
}
finally 碼。conn.setAutoCommit(false),BaseDao 不自行提交/回滾。PreparedStatement 參數綁定,絕不拼接 SQL 字串。