14.數(shù)據(jù)庫連接池【C3P0、阿里Druid、Spring JDBC】

數(shù)據(jù)庫連接池

概念: 一個容器(集合),存放數(shù)據(jù)庫連接的容器。當(dāng)系統(tǒng)初始化好后,容器被創(chuàng)建,容器中會申請一些連接對象,當(dāng)用戶來訪問數(shù)據(jù)庫時,從容器中獲取連接對象,當(dāng)用戶訪問完之后,會將連接對象歸還給容器。

好處:

  1. 節(jié)約資源
  2. 用戶訪問高效

技術(shù)支持:

  1. C3P0:數(shù)據(jù)庫連接池技術(shù)
  2. Druid:【很牛逼】數(shù)據(jù)庫連接池實(shí)現(xiàn)技術(shù),阿里巴巴提供

一、標(biāo)準(zhǔn)接口【javax.sql.DataSource】【具體實(shí)現(xiàn)由數(shù)據(jù)庫廠商去完成】

javax.sql.DataSource接口中的方法:

  • Connection getConnection():獲取連接
  • Connection.close():如果連接對象Connection是從連接池中獲取的,那么調(diào)用Connection.close()方法,則不再會關(guān)閉連接了。

二、C3P0數(shù)據(jù)庫連接池技術(shù)

1.使用步驟

  1. 導(dǎo)包jar:
    • 數(shù)據(jù)庫驅(qū)動包【前提】
    • c3p0-0.9.5.2.jar
    • mchange-commons-java-0.2.12.jar
  2. 定義配置文件
    • 名稱:c3p0.properties 或者 c3p0-config.xml
    • 路徑:src目錄下
  3. 創(chuàng)建核心對象 數(shù)據(jù)庫連接池對象 ComboPooledDataSource
  4. 獲取連接:getConnection(),執(zhí)行業(yè)務(wù)邏輯
  5. 歸還連接:Connection.close()

2.代碼實(shí)現(xiàn)

// 對應(yīng)的包
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

# ---------------------------------------- #

// 1.創(chuàng)建數(shù)據(jù)庫連接池對象【使用默認(rèn)配置,傳入?yún)?shù)則使用對應(yīng)的配置】
DataSource ds = new ComboPooledDataSource();

// 2.獲取連接對象
Connection conn = ds.getConnection();

// 3.業(yè)務(wù)邏輯
String sql = "create table student(" +
        "id int primary key auto_increment," +
        "name varchar(10)," +
        "age int," +
        "gender char(3)," +
        "birthday Date)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.executeUpdate();
ps.close();

// 4. 歸還連接對象
conn.close();

四、Druid數(shù)據(jù)庫連接池技術(shù),【阿里巴巴提供】

1.使用步驟

  1. 導(dǎo)入 druid-1.0.9.jar 包【也得導(dǎo)入數(shù)據(jù)庫驅(qū)動包】
  2. 定義配置文件
    • 可以是 properties 形式
    • 可以叫任意名稱,可以放在任意目錄下
  3. 加載配置文件:推薦 properties
  4. 獲取數(shù)據(jù)庫連接池對象:通過工廠類來獲取
    • DruidDataSourceFactory
  5. 獲取連接: getConnection

2. 代碼實(shí)現(xiàn)

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 DruidLearn {

    public static void main(String[] args) throws Exception {
        // 1.加載配置文件
        Properties pro = new Properties();
        InputStream in = DruidLearn.class
                         .getClassLoader()
                         .getResourceAsStream("druid.properties");
        pro.load(in);

        // 2.獲取連接池對象
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);

        // 3.獲取連接
        Connection conn = ds.getConnection();

        // 4.執(zhí)行力業(yè)務(wù)邏輯
        String sql1 = "create table user(id int primary key auto_increment,name varchar(10),password varchar(16))";
        PreparedStatement ps = conn.prepareStatement(sql1);
        int res = ps.executeUpdate();
        String sql2 = "insert into user values(null,'曉慶','abc123'),(null,'小竹','123abc')";
        ps = conn.prepareStatement(sql2);
        int res2 = ps.executeUpdate();
        String sql3 = "select * from user";
        ps = conn.prepareStatement(sql3);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) { int id = rs.getInt("id");String name = rs.getString("name");String password = rs.getString("password");System.out.println("編號:" + id + " 姓名:" + name + " 密碼:" + password); }

        // 5.釋放資源
        rs.close();
        ps.close();
        // 6.歸還資源
        conn.close();
    }
}

五、封裝一個Druid工具類JDBCUtils

  1. 提供靜態(tài)代碼塊加載排至文件,初始化連接池對象
  2. 提供的方法:
    • 獲取連接池的方法
    • 通過數(shù)據(jù)庫連接池獲取連接
    • 釋放資源
package JDBCUtils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils {
    /**
     * 1.定義成員變量 DateSource 連接池
     */
    private static DataSource ds;

    /**
     * 2.加載配置文件
     */
    static {
        try{
            Properties pro = new Properties();
            pro.load(JDBCUtils.class.getClassLoader()
                    .getResourceAsStream("druid.properties"));

            // 根據(jù)工廠類獲取數(shù)據(jù)庫連接池對象 SataSource
            ds = DruidDataSourceFactory.createDataSource(pro);

        } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }
    }

    /**
     * 獲取連接池
     */
    public static DataSource getDataSource() {
        return ds;
    }

    /**
     * 獲取連接
     */
    public static Connection getConnection() {
        try { return ds.getConnection(); } catch (Exception e) { e.printStackTrace();return null; }
    }

    /**
     * 釋放資源
     */

    public static void close(Statement stmt, Connection conn) {
        if(stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } }
        if(conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }
    }

    /**
     * 釋放資源; 重載
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if(rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } }
        close(stmt, conn);
    }
}

六、Spring JDBC

Spring 框架對JDBC的簡單封裝,提供了一個JdbcTemplate對象簡化JDBC的開發(fā)

1.操作步驟【使用上方實(shí)現(xiàn)的JDBCUtils工具箱類】

  1. 導(dǎo)入jar包,例如:
    • commons-logging-1.2.jar;
    • spring-beans-5.0.0.RELEASE.jar;
    • spring-core-5.0.0.RELEASE.jar;
    • spring-jdbc-5.0.0.RELEASE.jar;
    • spring-tx-5.0.0.RELEASE.jar;
  2. 創(chuàng)建JdbcTemplate對象。依賴于數(shù)據(jù)源 DataSource【從JDBCUtils獲得】
    • JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource())
  3. 調(diào)用JdbcTemplate的方法來完成CRUD的操作

2.JdbcTemplate類中的方法

  1. int update(String sql, ...): 執(zhí)行DML語句,增、刪、改語句。
  2. Map<String,Object> QueryForMap(String sql, ...): 查詢結(jié)果將結(jié)果集封裝成map集合,將列名作為key,將值作為value,將這條記錄封裝為一個map集合。
    • 注意:此方法查詢的結(jié)果集長度只能是【1】,也就是只能是一條記錄。
  3. List<Map<String,Object>> queryForList(String sql, ...): 查詢結(jié)果將結(jié)果集封裝為list集合
    • 注意:將每一條記錄封裝為一個Map集合,再將Map集合在到List集合中
  4. List<?> query(String sql, RowMapper<?> rm):查詢結(jié)果,將結(jié)果封裝為JavaBean對象。
    • 參數(shù):RowMapper接口:一般使用 BeanPropertyRowMapper實(shí)現(xiàn)類。當(dāng)然可以重寫內(nèi)部的mapRow抽象方法.完成數(shù)據(jù)到JavaBean的自動封裝

    new BeanPropertyMapper<E>(E.class):【E必須是JavaBean規(guī)范類,內(nèi)部的反射機(jī)制才好工作!

  5. E queryForObject(String sql, E.class): 查詢結(jié)果,將結(jié)果封裝為對象,一般為基本數(shù)據(jù)類型對象。
    • 注意: 一般用于聚合函數(shù)的查詢

使用JdbcTemplate中的方法,得到JdbcTemplate對象后,直接進(jìn)行SQL操作,不需要任何額外申請資源或者釋放資源的操作!資源用完了就釋放,結(jié)果集也是Map,List或者基本數(shù)據(jù)類型的包裝類

3.案例展示

代碼中使用JDBCUtils工具類是上面所描述的,Student類包含屬性【int id,String name,int age,String gender】,JavaBean規(guī)范類,代碼略!

package jdbcTemplate;

import JDBCUtils.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class JDBCTemplate {

    // 獲取JDBCTemplate對象
    private static JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    // 創(chuàng)建一張表格
    public static void create() {
        String sql = "create table student(" +
                "id int primary key auto_increment," +
                "name varchar(10)," +
                "age int," +
                "gender varchar(6))";
        int count = template.update(sql);
        System.out.println(count);
    }

    // 添加一些記錄
    public static void insert() {
        String sql = "insert into student values " +
                "(null,?,?,?)," +
                "(null,?,?,?);";
        int count = template.update(sql, "曉慶",18,"女","洪祥",20,"男");
        System.out.println(count);
    }

    // 修改記錄
    public static void update() {
        String sql = "update student set age = ? where name = ?";
        int res = template.update(sql, 22, "小竹");
        System.out.println(res);
    }

    // 刪除一些記錄
    public static void delect() {
        String sql = "delete from student where name in (?, ?)";
        int res = template.update(sql,"曉慶", "洪祥");
        System.out.println(res);
    }

    /**
     * 查詢操作
     */
    // queryForMap - 查詢的結(jié)果記錄值允許一條!
    public static void queryForMap() {
        String sql = "select * from student where name=?";
        Map<String, Object> map = template.queryForMap(sql, "曉慶");
        System.out.println(map);
    }

    // 5.查詢所有記錄,將其封裝為List
    public static void queryForList() {
        String sql = "select * from student";
        List<Map<String, Object>> list = template.queryForList(sql);
        for (Map<String, Object> map : list) {
            System.out.println(map);
        }
    }

    // 6.查詢所有記錄,將其封裝為Student對象的List集合【接口方法重寫】
    public static void queryOne() {
        String sql = "select * from student";
        List<Student> list = template.query(sql,new RowMapper<Student>() {

            /**
             * mapRow的返回值是一個對象而不是List集合,
             * 說明參數(shù)ResultSet是遍歷查詢的每個結(jié)果
             * */
            @Override
            public Student mapRow(ResultSet rs, int i) throws SQLException {
                Student student = new Student();
                student.setId(rs.getInt("id"));
                student.setName(rs.getString("name"));
                student.setAge(rs.getInt("age"));
                student.setGender(rs.getString("gender"));
                return student;
            }
        });

        for (Student student : list) {
            System.out.println(student);
        }
    }

    // 7.查詢所有記錄,將其封裝為Student對象的List集合
    public static void queryTwo() {
        String sql = "select * from student;";
        List<Student> list = template.query(sql, new BeanPropertyRowMapper<>(Student.class));
        for (Student student : list) {
            System.out.println(student);
        }
    }


    // 8.查詢總記錄數(shù)
    public static void queryAgg() {
        String sql = "select count(*) number from student";
        Long total = template.queryForObject(sql,Long.class);
        System.out.println(total);
    }

    public static void main(String[] args) {
        // create();
        // insert();
        // update();
        // delect();

        /*查詢操作!*/
        // queryForMap();
        // queryForList();
        // queryOne();
        // queryTwo();
        // queryAgg();

    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容