首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JDBC 核心完全指南:架構模式、程式設計步驟、CRUD 完整實戰與連接池整合

     編輯:Java 相關知識

JDBC (Java Database Connectivity) 是 Java 訪問關係型資料庫的標準 API。本文系統梳理 **JDBC 兩層/三層架構、核心介面體系、標準程式設計六步驟、PreparedStatement 防注入 CRUD 範本、事務控制、連接池 (HikariCP) 整合**,提供可直接落地生產的分層代碼結構。

一、JDBC 架構模式

架構特點適用場景
兩層 (Client/Server)Java App 直連 DB,邏輯與資料存取混雜桌面應用、簡單工具、原型驗證
三層 (Presentation/Business/Data)中間層封裝業務邏輯,Controller-Service-DAO 分層企業級 Web 系統、微服務、標準分層架構

現代開發**強烈建議採用三層架構**,並配合 Spring/JPA/MyBatis 等 ORM 框架;理解原生 JDBC 有助於排查框架底層問題。

二、核心介面體系

  • Driver:資料庫廠商實現,註冊至 DriverManager。
  • Connection:資料庫會話,管理事務、建立 Statement。
  • Statement:靜態 SQL 執行。
  • PreparedStatement:預編譯 SQL,**防 SQL 注入、效能優化(執行計畫緩存)**,主力選擇。
  • CallableStatement:呼叫預存程序。
  • ResultSet:結果集游標,支援順向/可捲動/可更新。
  • DataSource:連接池核心介面,替代 DriverManager。

三、標準六步驟

// 1. 載入驅動 (JDBC 4.0+ 可省略,SPI 自動發現)
Class.forName("com.mysql.cj.jdbc.Driver");

// 2. 建立連接
Connection conn = DriverManager.getConnection(URL, USER, PASS);

// 3. 建立 Statement
PreparedStatement ps = conn.prepareStatement(SQL);

// 4. 綁定參數
ps.setString(1, "value");
ps.setInt(2, 100);

// 5. 執行
ResultSet rs = ps.executeQuery(); // 查詢
int rows = ps.executeUpdate();    // 增刪改

// 6. 處理結果 / 釋放資源
try (conn; ps; rs) { ... } // Java 7+ try-with-resources 自動關閉

四、分層 CRUD 完整實戰範例

實體類

public class Goddess {
    private Integer id, age, sex, isDel;
    private String userName, email, mobile, createUser, updateUser;
    private Date birthday, createDate, updateDate;
    // Getter/Setter/Builder 省略
}

資料庫工具類

public class DbUtil {
    private static final String URL = "jdbc:mysql://localhost:3306/imooc?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASS = "123456";

    static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (Exception e) { throw new ExceptionInInitializerError(e); } }

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASS);
    }
}

DAO 介面與實現


public interface GoddessDao {
    void insert(Goddess g);
    void update(Goddess g);
    void deleteById(int id);
    Goddess getById(int id);
    List<Goddess> listAll();
}

public class GoddessDaoImpl implements GoddessDao {
    private static final String INSERT_SQL = "INSERT INTO imooc_goddess(user_name,sex,age,birthday,email,mobile,create_user,create_date,update_user,update_date,is_del) VALUES(?,?,?,?,?,?,?,NOW(),?,NOW(),?)";
    private static final String UPDATE_SQL = "UPDATE imooc_goddess SET user_name=?,sex=?,age=?,birthday=?,email=?,mobile=?,update_user=?,update_date=NOW(),is_del=? WHERE id=?";
    private static final String DELETE_SQL = "DELETE FROM imooc_goddess WHERE id=?";
    private static final String GET_SQL = "SELECT * FROM imooc_goddess WHERE id=?";
    private static final String LIST_SQL = "SELECT * FROM imooc_goddess WHERE is_del=0";

    @Override
    public void insert(Goddess g) {
        executeUpdate(INSERT_SQL, g.getUserName(), g.getSex(), g.getAge(), g.getBirthday(),
                g.getEmail(), g.getMobile(), g.getCreateUser(), g.getUpdateUser(), g.getIsDel());
    }

    @Override
    public void update(Goddess g) {
        executeUpdate(UPDATE_SQL, g.getUserName(), g.getSex(), g.getAge(), g.getBirthday(),
                g.getEmail(), g.getMobile(), g.getUpdateUser(), g.getIsDel(), g.getId());
    }

    @Override
    public void deleteById(int id) {
        executeUpdate(DELETE_SQL, id);
    }

    @Override
    public Goddess getById(int id) {
        return querySingle(GET_SQL, this::mapRow, id);
    }

    @Override
    public List<Goddess> listAll() {
        return queryList(LIST_SQL, this::mapRow);
    }

    // 通用執行模板
    private void executeUpdate(String sql, Object... params) {
        try (Connection conn = DbUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            bindParams(ps, params);
            ps.executeUpdate();
        } catch (SQLException e) { throw new RuntimeException(e); }
    }

    private <T> T querySingle(String sql, RowMapper<T> mapper, Object... params) {
        try (Connection conn = DbUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            bindParams(ps, params);
            try (ResultSet rs = ps.executeQuery()) {
                return rs.next() ? mapper.mapRow(rs) : null;
            }
        } catch (SQLException e) { throw new RuntimeException(e); }
    }

    private <T> List<T> queryList(String sql, RowMapper<T> mapper, Object... params) {
        List<T> list = new ArrayList<>();
        try (Connection conn = DbUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            bindParams(ps, params);
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) list.add(mapper.mapRow(rs));
            }
        } catch (SQLException e) { throw new RuntimeException(e); }
        return list;
    }

    private void bindParams(PreparedStatement ps, Object[] params) throws SQLException {
        for (int i = 0; i < params.length; i++) ps.setObject(i + 1, params[i]);
    }

    private Goddess mapRow(ResultSet rs) throws SQLException {
        Goddess g = new Goddess();
        g.setId(rs.getInt("id"));
        g.setUserName(rs.getString("user_name"));
        g.setSex(rs.getInt("sex"));
        g.setAge(rs.getInt("age"));
        g.setBirthday(rs.getDate("birthday"));
        g.setEmail(rs.getString("email"));
        g.setMobile(rs.getString("mobile"));
        g.setCreateUser(rs.getString("create_user"));
        g.setCreateDate(rs.getTimestamp("create_date"));
        g.setUpdateUser(rs.getString("update_user"));
        g.setUpdateDate(rs.getTimestamp("update_date"));
        g.setIsDel(rs.getInt("is_del"));
        return g;
    }

    @FunctionalInterface
    interface RowMapper<T> { T mapRow(ResultSet rs) throws SQLException; }
}

五、事務控制


public void transfer(int fromId, int toId, int amount) {
    Connection conn = null;
    try {
        conn = DbUtil.getConnection();
        conn.setAutoCommit(false); // 開啟事務

        // 扣減
        executeUpdate(conn, "UPDATE account SET balance=balance-? WHERE id=?", amount, fromId);
        // 增加
        executeUpdate(conn, "UPDATE account SET balance=balance+? WHERE id=?", amount, toId);

        conn.commit();
    } catch (Exception e) {
        if (conn != null) try { conn.rollback(); } catch (SQLException ignored) {}
        throw new RuntimeException(e);
    } finally {
        if (conn != null) try { conn.setAutoCommit(true); conn.close(); } catch (SQLException ignored) {}
    }
}

private void executeUpdate(Connection conn, String sql, Object... params) throws SQLException {
    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        bindParams(ps, params);
        ps.executeUpdate();
    }
}

六、連接池整合:HikariCP(生產標準)


// Maven 依賴
// com.zaxxer:HikariCP:5.0.1

public class DataSourceUtil {
    private static HikariDataSource ds;

    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/imooc?useSSL=false&serverTimezone=UTC");
        config.setUsername("root");
        config.setPassword("123456");
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        config.setPoolName("GoddessPool");
        ds = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    public static void close() { if (ds != null) ds.close(); }
}

將 DbUtil.getConnection() 改為委派 DataSourceUtil.getConnection() 即可無縫切換至連接池。

七、最佳實踐檢核表

  • ✅ **全程使用 PreparedStatement**,拒絕字串拼接 SQL。
  • ✅ **try-with-resources** 確保連接/Statement/ResultSet 釋放。
  • ✅ **連接池**為必備,禁用 DriverManager 直連生產庫。
  • ✅ **事務邊界**明確:Service 層控制事務,DAO 不自行 commit/rollback。
  • ✅ **異常轉換**:SQLException 包裝為非受檢異常向上拋出,避免汙染業務代碼。
  • ✅ **SQL 註解與格式化**:多行字串保持可讀性,便於慢查詢分析。

掌握原生 JDBC 分層實戰,是理解 Spring JDBC Template、MyBatis、JPA 等框架底層原理的基石。

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