DAO (Data Access Object) 模式是 Java EE 經典設計模式,實現業務邏輯與數據訪問層分離。本文通過完整代碼示例,展示如何基於 JDBC 封裝工具類、定義領域模型、設計 DAO 接口與實現類,構建可復用、可維護的數據訪問層。
| 組件 | 職責 | 命名慣例 |
|---|---|---|
| DAO 接口 | 定義數據訪問契約 | XxxDao |
| DAO 實現類 | 具體 SQL 執行邏輯 | XxxDaoImpl |
| 領域模型 (DTO/VO) | 業務數據載體 | Xxx (如 Person) |
| 工具類 | 連接管理、資源關閉 | DBUtils / JdbcUtil |
| 配置文件 | 數據庫連接參數外部化 | db-config.properties |
DaoTest01/
├── src/
│ ├── com.util.db/
│ │ └── DBUtils.java # JDBC 工具類
│ ├── com.vae.domain/
│ │ └── Person.java # 領域模型
│ ├── com.vae.dao/
│ │ └── PersonDao.java # DAO 接口
│ └── com.vae.dao.impl/
│ └── PersonDaoImpl.java # DAO 實現
└── resources/
└── db-config.properties # 配置文件
jdbc.url=jdbc:mysql://localhost:3306/jdbcdb
jdbc.username=root
jdbc.password=smyh
jdbc.driver=com.mysql.jdbc.Driver
package com.util.db;
import java.sql.*;
import java.util.ResourceBundle;
public class DBUtils {
// 靜態常量
public static String URL;
public static String USERNAME;
public static String PASSWORD;
public static String DRIVER;
// 載入配置文件
private static ResourceBundle rb = ResourceBundle.getBundle("com.util.db.db-config");
// 私有構造器,防止實例化
private DBUtils() {}
// 靜態代碼塊:類載入時執行一次,載入驅動
static {
URL = rb.getString("jdbc.url");
USERNAME = rb.getString("jdbc.username");
PASSWORD = rb.getString("jdbc.password");
DRIVER = rb.getString("jdbc.driver");
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new ExceptionInInitializerError("載入 JDBC 驅動失敗: " + e.getMessage());
}
}
// 獲取連接
public static Connection getConnection() {
try {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("獲取數據庫連接失敗", e);
}
}
// 關閉資源(支援可變參數,兼容無 ResultSet 場景)
public static void close(AutoCloseable... resources) {
for (AutoCloseable res : resources) {
if (res != null) {
try {
res.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
package com.vae.domain;
public class Person {
private int id;
private String name;
private int age;
private String description;
// 全參構造器
public Person(int id, String name, int age, String description) {
this.id = id;
this.name = name;
this.age = age;
this.description = description;
}
// 無 ID 構造器(新增時使用)
public Person(String name, int age, String description) {
this.name = name;
this.age = age;
this.description = description;
}
public Person() {}
// Getter/Setter 省略...
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
@Override
public String toString() {
return "Person[id=" + id + ", name=" + name + ", age=" + age + ", desc=" + description + "]";
}
}
package com.vae.dao;
import com.vae.domain.Person;
import java.sql.SQLException;
import java.util.List;
public interface PersonDao {
void add(Person p) throws SQLException;
void update(Person p) throws SQLException;
void delete(int id) throws SQLException;
Person findById(int id) throws SQLException;
List findAll() throws SQLException;
}
package com.vae.dao.impl;
import com.util.db.DBUtils;
import com.vae.dao.PersonDao;
import com.vae.domain.Person;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class PersonDaoImpl implements PersonDao {
@Override
public void add(Person p) throws SQLException {
String sql = "INSERT INTO person(name, age, description) VALUES (?, ?, ?)";
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1, p.getName());
ps.setInt(2, p.getAge());
ps.setString(3, p.getDescription());
ps.executeUpdate();
} finally {
DBUtils.close(ps, conn);
}
}
@Override
public void update(Person p) throws SQLException {
String sql = "UPDATE person SET name=?, age=?, description=? WHERE id=?";
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1, p.getName());
ps.setInt(2, p.getAge());
ps.setString(3, p.getDescription());
ps.setInt(4, p.getId());
ps.executeUpdate();
} finally {
DBUtils.close(ps, conn);
}
}
@Override
public void delete(int id) throws SQLException {
String sql = "DELETE FROM person WHERE id=?";
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.executeUpdate();
} finally {
DBUtils.close(ps, conn);
}
}
@Override
public Person findById(int id) throws SQLException {
String sql = "SELECT id, name, age, description FROM person WHERE id=?";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
rs = ps.executeQuery();
if (rs.next()) {
Person p = new Person();
p.setId(rs.getInt("id"));
p.setName(rs.getString("name"));
p.setAge(rs.getInt("age"));
p.setDescription(rs.getString("description"));
return p;
}
return null;
} finally {
DBUtils.close(rs, ps, conn);
}
}
@Override
public List findAll() throws SQLException {
String sql = "SELECT id, name, age, description FROM person";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
List list = new ArrayList<>();
try {
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
Person p = new Person();
p.setId(rs.getInt("id"));
p.setName(rs.getString("name"));
p.setAge(rs.getInt("age"));
p.setDescription(rs.getString("description"));
list.add(p);
}
return list;
} finally {
DBUtils.close(rs, ps, conn);
}
}
}
package com.vae.test;
import com.vae.dao.PersonDao;
import com.vae.dao.impl.PersonDaoImpl;
import com.vae.domain.Person;
import java.sql.SQLException;
import java.util.List;
public class DaoTest {
public static void main(String[] args) {
PersonDao dao = new PersonDaoImpl();
try {
// 1. 新增
Person p1 = new Person("張三", 25, "工程師");
dao.add(p1);
System.out.println("新增成功");
// 2. 查詢所有
List list = dao.findAll();
list.forEach(System.out::println);
// 3. 按 ID 查詢
Person p = dao.findById(1);
System.out.println("ID=1: " + p);
// 4. 更新
if (p != null) {
p.setAge(26);
p.setDescription("高級工程師");
dao.update(p);
System.out.println("更新成功");
}
// 5. 刪除
dao.delete(1);
System.out.println("刪除成功");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
DAO 模式是企業級 Java 應用數據訪問層的基石。通過本文的完整實現,您已掌握從配置、工具類、領域模型、接口設計到具體 CRUD 實現的全流程。建議在實際專案中引入連接池與事務管理,逐步向成熟 ORM 框架遷移。