数据库连接池

数据库连接池是个容器, 负责分配, 管理数据库连接 (Connection).

数据库连接池允许应用程序重复使用一个现有的数据库连接, 而不是再重新建立一个. 从而减少资源浪费.

数据库连接池会自动释放超过最大空闲时间的数据库连接 (强制释放), 来避免因为没有释放数据库连接而引起的数据库连接遗漏.

使用数据库连接池的好处:

  • 资源可以重用
  • 提升系统响应速度
  • 避免数据库连接遗漏

在通常情况下使用JDBC, 有可能会反复地创建和销毁 Connection对象. 这样重复创建销毁的过程特别耗费计算机的性能和时间.

而数据库使用了数据库连接池后,就能达到Connection对象的复用.

连接池是在一开始就创建好了一些连接 (Connection) 对象存储起来. 用户需要连接数据库时, 不需要自己创建连接, 而只需要从连接池中获取一个连接进行使用, 使用完毕后再将连接对象归还给连接池; 这样就可以起到资源重用, 也节省了频繁创建连接销毁连接所花费的时间, 从而提升了系统响应的速度.

常见的数据库连接池有:

  • DBCP
  • C3P0
  • Druid

Druid

配置 Druid

  • 下载Druid jar包, 并导入:

    在项目中, 将下载好的jar包放入项目的 lib目录中.

    • 然后点击鼠标右键–>Add as Library (添加为库).
    • 在添加为库文件的时候,有如下三个选项:
      • Global Library: 全局有效

      • Project Library: 项目有效

      • Module Library: 模块有效

        选择Module Library.

  • 在项目目录下定义Druid配置文件 druid.properties:

    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true
    username=root
    password=1234
    # 初始化连接数量
    initialSize=5
    # 最大连接数
    maxActive=10
    # 最大等待时间
    maxWait=3000
    
  • 加载配置文件:

    Properties prop = new Properties();
    prop.load(new FileInputStream("demo/src/druid.properties"));
    

使用 Druid

Java中从数据库连接池获取连接对象, 使用的是官方提供的数据库连接池标准接口, 由第三方组织实现此接口. 该接口提供了获取连接的功能:

Connection getConnection()
                  throws SQLException

因此, 使用Druid获取数据库连接还需要以下两步:

  • 获取数据库连接池对象:

     DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    
  • 从数据库连接池中获取连接 (Connection):

    Connection connection = dataSource.getConnection();
    

操作实例

需求分析

完成商品品牌数据的增删改查操作

  • 查询:查询所有数据
  • 添加:添加品牌
  • 修改:根据id修改
  • 删除:根据id删除

环境准备

  1. 创建数据库表:

    -- 删除tb_brand表
    DROP TABLE IF EXISTS tb_brand;
    -- 创建tb_brand表
    CREATE TABLE tb_brand (
        id INT PRIMARY KEY AUTO_INCREMENT, -- id 主键
        brand_name VARCHAR(20), -- 品牌名称
        company_name VARCHAR(20), -- 企业名称
        ordered INT, -- 排序字段
        description VARCHAR(100), -- 描述信息
        status INT -- 状态:0:禁用  1:启用
    );
    -- 添加数据
    INSERT INTO tb_brand (brand_name, company_name, ordered, description, status)
    VALUES ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
        ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
        ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
  2. 创建 pojo包, 并在包中添加 Brand实体类:

    package pojo;
    
    /**
    * 品牌
    */
    public class Brand {
    
        private Integer id; // id 主键
        private String brandName; // 品牌名称
        private String companyName; // 企业名称
        private Integer ordered; // 排序字段
        private String description; // 描述信息
        private Integer status; // 状态:0:禁用  1:启用
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getBrandName() {
            return brandName;
        }
    
        public void setBrandName(String brandName) {
            this.brandName = brandName;
        }
    
        public String getCompanyName() {
            return companyName;
        }
    
        public void setCompanyName(String companyName) {
            this.companyName = companyName;
        }
    
        public Integer getOrdered() {
            return ordered;
        }
    
        public void setOrdered(Integer ordered) {
            this.ordered = ordered;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public Integer getStatus() {
            return status;
        }
    
        public void setStatus(Integer status) {
            this.status = status;
        }
    
        @Override
        public String toString() {
            return "Brand{" +
                    "id=" + id +
                    ", brandName='" + brandName + '\'' +
                    ", companyName='" + companyName + '\'' +
                    ", ordered=" + ordered +
                    ", description='" + description + '\'' +
                    ", status=" + status +
                    '}';
        }
    }
    

实现操作

package dao;

import pojo.Brand;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.Properties;

/**
 * 品牌数据的增删改查操作
 */
public class BrandDAO {

    private static DataSource dataSource;

    // 获取Connection:
    static {
        try {
            // - 导入jar包 & 定义配置文件
            // - 加载配置文件
            Properties prop = new Properties();
            prop.load(new FileInputStream("demo/src/druid.properties"));
            // - 获取连接池对象
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查询所有
     * 1. SQL: SELECT * FROM tb_brand
     * 2. 参数: 不需要
     * 3. 结果: ArrayList<Brand>
     */
    public ArrayList<Brand> selectAll() throws Exception{
        // 1. 获取数据库连接Connection
        Connection conn = dataSource.getConnection();

        // *2. 定义SQL
        String sql = "SELECT * FROM tb_brand";

        // 3. 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
      
        // *4. 设置参数
      
        // 5. 执行SQL
        ResultSet rs = pstmt.executeQuery();

        // *6. 处理结果: ArrayList<Brand>
        Brand brand = null;
        ArrayList<Brand> brands = new ArrayList<>();
        // - 遍历结果集
        while (rs.next()) {
            // 1. 获取数据
            int id = rs.getInt("id");
            String brandName = rs.getString("brand_name");
            String companyName = rs.getString("company_name");
            int ordered = rs.getInt("ordered");
            String description = rs.getString("description");
            int status = rs.getInt("status");

            // 2. 封装Brand对象
            brand = new Brand();
            brand.setId(id);
            brand.setCompanyName(companyName);
            brand.setOrdered(ordered);
            brand.setDescription(description);
            brand.setStatus(status);

            // 3. 装载ArrayList集合
            brands.add(brand);
        }

        // 7. 释放资源
        rs.close();
        pstmt.close();
        conn.close();

        // 8. 返回结果
        return brands;
    }

    /**
     * 添加
     * 1. SQL:
         INSERT INTO tb_brand(
            brand_name,
            company_name,
            ordered,
            description,
            status)
         VALUES(?,?,?,?,?)
     * 2. 参数: 除了id之外的所有参数信息
     * 3. 结果: boolean
     */
    public boolean add(Brand brand) throws Exception{
        // 1. 获取数据库连接Connection
        Connection conn = dataSource.getConnection();

        // *2. 定义SQL
        String sql = """
                INSERT INTO tb_brand(
                    brand_name,
                    company_name,
                    ordered,
                    description,
                    status)
                VALUES(?,?,?,?,?)""";

        // 3. 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // *4. 设置参数
        pstmt.setString(1, brand.getBrandName());
        pstmt.setString(2, brand.getCompanyName());
        pstmt.setInt(3, brand.getOrdered());
        pstmt.setString(4, brand.getDescription());
        pstmt.setInt(5, brand.getStatus());

        // 5. 执行SQL
        int count = pstmt.executeUpdate(); // 返回影响的行数

        // 6. 释放资源
        pstmt.close();
        conn.close();

        // 7. 返回结果
        return count > 0;
    }

    /**
     * 修改
     * 1. SQL:
         UPDATE tb_brand
         SET brand_name=?,
            company_name=?,
            ordered=?,
            description=?,
            status=?
         WHERE id=?
     * 2. 参数: 所有
     * 3. 结果: boolean
     */
    public boolean update(Brand brand) throws Exception{
        // 1. 获取数据库连接Connection
        Connection conn = dataSource.getConnection();

        // *2. 定义SQL
        String sql = """
                UPDATE tb_brand
                SET brand_name=?,
                    company_name=?,
                    ordered=?,
                    description=?,
                    status=?
                WHERE id=?""";

        // 3. 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // *4. 设置参数
        pstmt.setString(1, brand.getBrandName());
        pstmt.setString(2, brand.getCompanyName());
        pstmt.setInt(3, brand.getOrdered());
        pstmt.setString(4, brand.getDescription());
        pstmt.setInt(5, brand.getStatus());
        pstmt.setInt(6, brand.getId());

        // 5. 执行SQL
        int count = pstmt.executeUpdate(); // 返回影响的行数

        // 6. 释放资源
        pstmt.close();
        conn.close();

        // 8. 返回结果
        return count > 0;
    }

    /**
     * 删除
     * 1. SQL:DELETE FROM tb_brand WHERE id=?
     * 2. 参数: id
     * 3. 结果: boolean
     */
    public boolean deleteById(int id) throws Exception{
        // 1. 获取数据库连接Connection
        Connection conn = dataSource.getConnection();

        // *2. 定义SQL
        String sql = "DELETE FROM tb_brand WHERE id=?";

        // 3. 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // *4. 设置参数
        pstmt.setInt(1, id);

        // 5. 执行SQL
        int count = pstmt.executeUpdate(); // 返回影响的行数

        // 6. 释放资源
        pstmt.close();
        conn.close();

        // 7. 返回结果
        return count > 0;
    }
}