首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 數據庫學習筆記:DAO 設計模式封裝 JDBC 實現增刪改查

     編輯:MySQL 綜合教學

MySQL 數據庫學習筆記:DAO 設計模式封裝 JDBC 實現增刪改查

DAO (Data Access Object) 模式是 Java EE 經典設計模式,實現業務邏輯與數據訪問層分離。本文通過完整代碼示例,展示如何基於 JDBC 封裝工具類、定義領域模型、設計 DAO 接口與實現類,構建可復用、可維護的數據訪問層。

一、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          # 配置文件

三、核心代碼實現

1. 數據庫配置文件 (db-config.properties)

jdbc.url=jdbc:mysql://localhost:3306/jdbcdb
jdbc.username=root
jdbc.password=smyh
jdbc.driver=com.mysql.jdbc.Driver

2. JDBC 工具類 (DBUtils.java)

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();
                }
            }
        }
    }
}

3. 領域模型 (Person.java)

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 + "]";
    }
}

4. DAO 接口 (PersonDao.java)

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;
}

5. DAO 實現類 (PersonDaoImpl.java)

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();
        }
    }
}

五、關鍵設計要點總結

  1. 配置外部化: 連接參數放在 properties 文件,環境遷移零代碼修改
  2. 資源管理: try-finally 確保連接/Statement/ResultSet 關閉,防止洩漏
  3. PreparedStatement: 防 SQL 注入、預編譯提升效能、支援批次操作
  4. 異常處理: 捕獲 SQLException 並拋出業務異常,上層統一處理
  5. 接口導向編程: 業務層依賴 PersonDao 接口,便於測試與替換實現
  6. 單一職責: 每個類職責單一,符合高內聚低耦合

六、進階優化方向

  • 連接池: 替換 DriverManager 為 HikariCP/Druid,複用連接
  • 事務管理: 引入 @Transactional 或編程式事務,保證 ACID
  • ORM 框架: MyBatis/Hibernate/JPA 替代手寫 SQL
  • 泛型 DAO: 抽象 BaseDao<T, ID> 減少樣板代碼
  • 分頁查詢: 封裝 PageHelper 或手寫 LIMIT/OFFSET

DAO 模式是企業級 Java 應用數據訪問層的基石。通過本文的完整實現,您已掌握從配置、工具類、領域模型、接口設計到具體 CRUD 實現的全流程。建議在實際專案中引入連接池與事務管理,逐步向成熟 ORM 框架遷移。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved