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

從零手寫 JDBC DataSource:簡易連線池實作教學

     編輯:Java 相關知識

為什麼要自己實作 DataSource?

DataSource 是 Java 操作資料庫的關鍵介面,主流持久化框架(Hibernate、MyBatis、Spring JDBC)皆建立在其之上。雖然生產環境建議使用成熟的連線池(DBCP、HikariCP、C3P0),但親手實作一個極簡版本,能深入理解連線池的核心機制:連線複用、同步控制、生命週期管理。

核心設計思路

  • 實作 javax.sql.DataSource 介面,滿足框架整合需求。
  • 使用 Collections.synchronizedList(new LinkedList<>()) 作為線程安全的連線容器。
  • 採用單例模式,確保全域只有一個池實例。
  • getConnection() 優先從池取出,池空則新建;freeConnection() 歸還連線。
  • 靜態區塊載入 JDBC 驅動,避免重複載入開銷。

完整程式碼

package com.lavasoft.simpledatesource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.LinkedList;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.io.PrintWriter;

/**
 * 簡易 DataSource 實作,示範連線池基本原理
 * @author leizhimin
 */
public class SimpleDateSource implements DataSource {
    private static final Log log = LogFactory.getLog(SimpleDateSource.class);
    
    // 資料庫連線參數(實際專案應外部化至設定檔)
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/testdb";
    private static final String USER = "root";
    private static final String PASSWORD = "leizhimin";

    // 連線池:線程安全的 LinkedList
    private static final LinkedList<Connection> pool = 
        (LinkedList<Connection>) Collections.synchronizedList(new LinkedList<Connection>());
    
    // 單例實例
    private static final SimpleDateSource INSTANCE = new SimpleDateSource();

    static {
        try {
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {
            log.error("找不到 JDBC 驅動類別!", e);
        }
    }

    private SimpleDateSource() {}

    public static SimpleDateSource getInstance() {
        return INSTANCE;
    }

    @Override
    public Connection getConnection() throws SQLException {
        synchronized (pool) {
            if (pool.size() > 0) {
                return pool.removeFirst(); // 復用現有連線
            }
            return createConnection(); // 池空則新建
        }
    }

    /** 歸還連線至池中 */
    public static void freeConnection(Connection conn) {
        if (conn != null) {
            pool.addLast(conn);
        }
    }

    private Connection createConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }

    // --- 以下為 DataSource 介面要求的方法,簡易實作多拋出 UnsupportedOperationException 或返回預設值 ---
    @Override public Connection getConnection(String u, String p) throws SQLException { return DriverManager.getConnection(URL, u, p); }
    @Override public PrintWriter getLogWriter() throws SQLException { return null; }
    @Override public void setLogWriter(PrintWriter out) throws SQLException {}
    @Override public void setLoginTimeout(int seconds) throws SQLException {}
    @Override public int getLoginTimeout() throws SQLException { return 0; }
    @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
}

關鍵點解析

1. 連線池的同步控制

synchronized (pool) 確保多執行緒環境下「取出/歸還」操作的原子性,避免同一連線被多執行緒同時使用。

2. 連線驗證與失效處理(生產級必備)

本範例為教學簡化,省略了連線有效性檢查。實務上應在 getConnection() 時執行 conn.isValid(1) 或執行 SELECT 1,失效則丟棄並重建。

3. 擴充方向

  • 引入設定檔(Properties/YAML)管理 URL、帳密、初始/最大池大小。
  • 啟動背景執行緒定期清理閒置超時、強制關閉的連線。
  • 完善 getLogWriter、setLoginTimeout 等標準介面方法。
  • 支援 JMX 監控池狀態(活躍/閒置數、等待執行緒數)。

總結

不到百行程式碼即完成核心功能,展示了連線池「借用-歸還」的基本模型。雖不適合直接用於生產,卻是理解 HikariCP 等高階池原理的最佳切入點。建議讀者嘗試加上「最大池大小限制」與「取得連線超時等待」機制,進一步完善。

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