14.数据库连接池【C3P0、阿里Druid、Spring JDBC】

数据库连接池

概念: 一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,当用户访问完之后,会将连接对象归还给容器。

好处:

  1. 节约资源
  2. 用户访问高效

技术支持:

  1. C3P0:数据库连接池技术
  2. Druid:【很牛逼】数据库连接池实现技术,阿里巴巴提供

一、标准接口【javax.sql.DataSource】【具体实现由数据库厂商去完成】

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

  • Connection getConnection():获取连接
  • Connection.close():如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不再会关闭连接了。

二、C3P0数据库连接池技术

1.使用步骤

  1. 导包jar:
    • 数据库驱动包【前提】
    • c3p0-0.9.5.2.jar
    • mchange-commons-java-0.2.12.jar
  2. 定义配置文件
    • 名称:c3p0.properties 或者 c3p0-config.xml
    • 路径:src目录下
  3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
  4. 获取连接:getConnection(),执行业务逻辑
  5. 归还连接:Connection.close()

2.代码实现

// 对应的包
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

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

// 1.创建数据库连接池对象【使用默认配置,传入参数则使用对应的配置】
DataSource ds = new ComboPooledDataSource();

// 2.获取连接对象
Connection conn = ds.getConnection();

// 3.业务逻辑
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数据库连接池技术,【阿里巴巴提供】

1.使用步骤

  1. 导入 druid-1.0.9.jar 包【也得导入数据库驱动包】
  2. 定义配置文件
    • 可以是 properties 形式
    • 可以叫任意名称,可以放在任意目录下
  3. 加载配置文件:推荐 properties
  4. 获取数据库连接池对象:通过工厂类来获取
    • DruidDataSourceFactory
  5. 获取连接: getConnection

2. 代码实现

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.执行力业务逻辑
        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. 提供静态代码块加载排至文件,初始化连接池对象
  2. 提供的方法:
    • 获取连接池的方法
    • 通过数据库连接池获取连接
    • 释放资源
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"));

            // 根据工厂类获取数据库连接池对象 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的开发

1.操作步骤【使用上方实现的JDBCUtils工具箱类】

  1. 导入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. 创建JdbcTemplate对象。依赖于数据源 DataSource【从JDBCUtils获得】
    • JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource())
  3. 调用JdbcTemplate的方法来完成CRUD的操作

2.JdbcTemplate类中的方法

  1. int update(String sql, ...): 执行DML语句,增、删、改语句。
  2. Map QueryForMap(String sql, ...): 查询结果将结果集封装成map集合,将列名作为key,将值作为value,将这条记录封装为一个map集合。
    • 注意:此方法查询的结果集长度只能是【1】,也就是只能是一条记录。
  3. List> queryForList(String sql, ...): 查询结果将结果集封装为list集合
    • 注意:将每一条记录封装为一个Map集合,再将Map集合在到List集合中
  4. List query(String sql, RowMapper rm):查询结果,将结果封装为JavaBean对象。
    • 参数:RowMapper接口:一般使用 BeanPropertyRowMapper实现类。当然可以重写内部的mapRow抽象方法.完成数据到JavaBean的自动封装

    new BeanPropertyMapper(E.class):【E必须是JavaBean规范类,内部的反射机制才好工作!

  5. E queryForObject(String sql, E.class): 查询结果,将结果封装为对象,一般为基本数据类型对象
    • 注意: 一般用于聚合函数的查询

使用JdbcTemplate中的方法,得到JdbcTemplate对象后,直接进行SQL操作,不需要任何额外申请资源或者释放资源的操作!资源用完了就释放,结果集也是Map,List或者基本数据类型的包装类

3.案例展示

代码中使用JDBCUtils工具类是上面所描述的,Student类包含属性【int id,String name,int age,String gender】,JavaBean规范类,代码略!

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

    // 创建一张表格
    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 - 查询的结果记录值允许一条!
    public static void queryForMap() {
        String sql = "select * from student where name=?";
        Map map = template.queryForMap(sql, "晓庆");
        System.out.println(map);
    }

    // 5.查询所有记录,将其封装为List
    public static void queryForList() {
        String sql = "select * from student";
        List> list = template.queryForList(sql);
        for (Map map : list) {
            System.out.println(map);
        }
    }

    // 6.查询所有记录,将其封装为Student对象的List集合【接口方法重写】
    public static void queryOne() {
        String sql = "select * from student";
        List list = template.query(sql,new RowMapper() {

            /**
             * mapRow的返回值是一个对象而不是List集合,
             * 说明参数ResultSet是遍历查询的每个结果
             * */
            @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 list = template.query(sql, new BeanPropertyRowMapper<>(Student.class));
        for (Student student : list) {
            System.out.println(student);
        }
    }


    // 8.查询总记录数
    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();

    }
}

你可能感兴趣的:(14.数据库连接池【C3P0、阿里Druid、Spring JDBC】)