druid 數據庫連接池技術的使用


在實際項目開發中訪問操作數據庫,肯定要使用到連接池技術,不僅可以提升數據庫操作效率,也在某種程度上提高了代碼質量。前面我們簡單介紹了 c3p0 連接池的使用,今天我們還是以操作 mysql 為例簡單介紹一下 druid 數據庫連接池技術的使用。

druid 是阿里技術團隊提供的一款優秀的開源數據庫連接池,在國內使用非常廣泛。作為后起之秀,其功能靈活強大穩定,性能也比 c3p0 要高,大有替代其它第三方數據庫連接池的趨勢。我們也推薦在項目和產品開發中優先考慮 druid 連接池技術的使用。

druid 的 GitHub 地址為:https://github.com/alibaba/druid (GitHub 訪問可能比較慢)
druid 的 Gitee 地址為:https://gitee.com/wangmt2000/druid


一、配置 druid 連接池

我們首先創建一個 JavaSE 的 Maven 項目,在 pom.xml 文件中導入 druid 和 mysql 的 jar 包。

我們可以從 https://mvnrepository.com 上進行查找有關各種 jar 包依賴的 xml 配置內容,復制粘貼到 pom.xml 即可。
druid 的 jar 包網址是:https://mvnrepository.com/artifact/com.alibaba/druid
mysql 連接 java 的驅動 jar 包網址是:https://mvnrepository.com/artifact/mysql/mysql-connector-java

我在 pom.xml 配置的都是當前最新版本的 jar 包,如下所示:

<!-- 導入 druid 的 jar 包 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>

<!-- 導入 mysql 的 jar 包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

配置好引用的 jar 包后,打開右側的 Maven 窗口,刷新一下,這樣 Maven 會自動下載所需的 jar 包文件。

然后在項目的 resources 資源目錄下創建 druid 的 properties 配置文件,properties 配置文件可以隨意命名,但是文件內容中每項配置的 key 必須是指定的名稱,這里我使用 druid.properties 作為配置文件的名稱,其文件內容如下所示:

# 數據庫連接參數
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testdb
username=root
password=123456

# 初始化連接的數量
initialSize=3
# 最大連接的數量
maxActive=20
# 獲取連接的最大等待時間(毫秒)
maxWait=3000

當然可選配置項有很多,上面列出的只是最常用的核心配置項,有關詳細的配置項列表,可以參看以下網址:
https://github.com/alibaba/druid/wiki/DruidDataSource配置 (GitHub 訪問可能比較慢)


二、使用 druid 連接池

使用 druid 連接池,主要是使用 DruidDataSourceFactory 根據 properties 配置文件內容創建出 DataSource 數據源對象,然后調用其 getConnection 方法獲取數據庫連接對象,拿到連接對象之后,其它的操作跟 JDBC 訪問數據庫的操作一模一樣,唯一的區別就是當調用連接的 close 方法時,底層不再是關閉銷毀連接對象,而是將連接對象放入到連接池中,以便后續新的請求到來時,直接拿去使用。具體代碼如下:

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

public class druidtest {
    public static void main(String[] args) throws Exception {

        //加載配置文件
        InputStream is = druidtest.class.getClassLoader().getResourceAsStream("druid.properties");
        Properties prop = new Properties();
        prop.load(is);

        //根據配置文件內容,創建出數據源對象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //通過數據源對象獲取數據庫連接
        //如果連接池中的連接已經被用完,則會等待一定的時間(所配置的時間)
        //如果等待超時,就會拋出異常
        Connection con = dataSource.getConnection();

        //執行 sql 語句,獲取並打印結果集
        String sql = "select e_id,e_name,e_age from employee";
        PreparedStatement pst = con.prepareStatement(sql);
        ResultSet rs = pst.executeQuery();
        while(rs.next()) {
            System.out.println(
                    rs.getInt("e_id") + "\t" +
                    rs.getString("e_name") + "\t" +
                    rs.getInt("e_age"));
        }

        //釋放資源
        rs.close();
        pst.close();

        //這里的關閉連接,並沒有關閉和銷毀連接
        //而是把連接對象,放入到連接池中,供后續訪問時直接拿去使用
        con.close();
    }
}

如果你之前基於 JDBC 編寫過通用的數據庫訪問類,那么將它改造為基於 druid 的數據庫訪問類,也是很容易的。
這里我提供一個相對比較完整的基於 druid 連接池的數據庫訪問類(具體細節就不詳細介紹了),內容如下所示:

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class jdbcHelper {
    private static DataSource dataSource;

    //靜態初始化,加載 properties 配置文件,創建數據源對象
    static {
        try {
            InputStream is =
                 druidtest.class.getClassLoader().getResourceAsStream("druid.properties");

            Properties prop = new Properties();
            prop.load(is);

            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    //通過數據源對象,獲取連接對象
    public static Connection getConnection() {
        Connection con = null;
        try {
            con = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    //釋放查詢操作相關的資源(結果集對象,SQL語句對象,歸還數據庫連接)
    public static void close(Connection con, Statement stat, ResultSet rs) {
        if (con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //釋放增刪改相關操作的資源(SQL語句對象,歸還數據庫連接)
    public static void close(Connection con, Statement stat) {
        close(con, stat, null);
    }

    //執行查詢 SQL 語句,返回查詢的單個值
    public static <T> T queryForValue(String sql, Class<T> returnType, Object... parameters) {
        T result = null;
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            con = dataSource.getConnection();
            pst = con.prepareStatement(sql);

            if (parameters.length > 0) {
                for (int i = 0; i < parameters.length; i++) {
                    pst.setObject(i + 1, parameters[i]);
                }
            }

            rs = pst.executeQuery();
            if (rs.next()) {
                result = returnType.cast(rs.getObject(1));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }

        return result;
    }

    //執行查詢 SQL 語句,返回查詢的單個實體對象
    public static <T> T queryForObject(String sql, Class<T> returnType, Object... parameters) {

        T result = null;
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {
            result = returnType.getConstructor().newInstance();
            con = dataSource.getConnection();
            pst = con.prepareStatement(sql);

            if (parameters.length > 0) {
                for (int i = 0; i < parameters.length; i++) {
                    pst.setObject(i + 1, parameters[i]);
                }
            }

            rs = pst.executeQuery();
            if (rs.next()) {
                ResultSetMetaData metaData = rs.getMetaData();
                int count = metaData.getColumnCount();
                for (int i = 1; i <= count; i++) {
                    String columnName = metaData.getColumnName(i);
                    Object value = rs.getObject(columnName);
                    PropertyDescriptor pd =
                            new PropertyDescriptor(columnName.toLowerCase(), returnType);
                    Method writeMethod = pd.getWriteMethod();
                    writeMethod.invoke(result, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }

        return result;
    }

    //執行查詢 SQL 語句,返回查詢的實體對象列表
    public static <T> List<T> queryForList(String sql, Class<T> returnType, Object... parameters) {
        List<T> list = new ArrayList<>();
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            con = dataSource.getConnection();
            pst = con.prepareStatement(sql);

            if (parameters.length > 0) {
                for (int i = 0; i < parameters.length; i++) {
                    pst.setObject(i + 1, parameters[i]);
                }
            }

            rs = pst.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int count = metaData.getColumnCount();

            while (rs.next()) {
                T bean = returnType.getConstructor().newInstance();
                for (int i = 1; i <= count; i++) {
                    String columnName = metaData.getColumnName(i);
                    Object value = rs.getObject(columnName);
                    PropertyDescriptor pd =
                            new PropertyDescriptor(columnName.toLowerCase(), returnType);
                    Method writeMethod = pd.getWriteMethod();
                    writeMethod.invoke(bean, value);
                }
                list.add(bean);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }

        return list;
    }

    //執行增刪改 SQL 語句,返回受影響的行數
    public static int executeSql(String sql,Object...parameters) {
        int count = 0;
        Connection con = null;
        PreparedStatement pst = null;
        try{
            con = dataSource.getConnection();
            pst = con.prepareStatement(sql);

            if (parameters.length > 0) {
                for (int i = 0; i < parameters.length; i++) {
                    pst.setObject(i + 1, parameters[i]);
                }
            }

            count = pst.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(con,pst);
        }

        return count;
    }
}

然后在 Maven 項目的 test 目錄下創建測試類,使用這個 druid 數據庫訪問類測試其使用方法:

import org.junit.Test;
import java.util.List;

public class jdbcHelperTest {

    @Test
    public void queryForValue() {
        //查詢員工數量
        String sql = "select count(*) from employee";
        Long value = jdbcHelper.queryForValue(sql,Long.class);
        System.out.println(value);
    }

    @Test
    public void queryForList() {
        //查詢所有員工
        String sql = "select * from employee";
        List<Employee> list = jdbcHelper.queryForList(sql, Employee.class);
        for(Employee emp : list) {
            System.out.println(emp);
        }
    }

    @Test
    public void queryForObject() {
        //查詢一條員工,並打印出來
        String sql = "select * from employee WHERE e_id=?";
        Employee emp = jdbcHelper.queryForObject(sql,Employee.class,1);
        System.out.println(emp);
    }

    @Test
    public void insert() {
        //添加一條新員工
        String sql = "insert into employee(e_id,e_name,e_age) values(?,?,?)";
        Object[] params = {6,"任天蓬",40};
        int result = jdbcHelper.executeSql(sql, params);
        System.out.println(result);
    }

    @Test
    public void update() {
        //通過員工id,修改員工的年齡
        String sql = "update employee set e_age=? where e_id=?";
        Object[] params = {38,6};
        int result = jdbcHelper.executeSql(sql, params);
        System.out.println(result);
    }

    @Test
    public void delete() {
        //通過員工姓名,刪除員工
        String sql = "DELETE FROM employee WHERE e_name=?";
        int result = jdbcHelper.executeSql(sql, "任天蓬");
        System.out.println(result);
    }
}

OK,以上只是簡單的 druid 連接池技術的介紹,總體來說使用起來很簡單,希望對大家有用。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM