数据库连接池

数据库连接池是个容器, 负责分配, 管理数据库连接 (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:

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

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

使用 Druid

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

1Connection getConnection()
2                  throws SQLException

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

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

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

    1Connection connection = dataSource.getConnection();
    

操作实例

需求分析

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

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

环境准备

  1. 创建数据库表:

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

     1package pojo;
     2
     3/**
     4* 品牌
     5*/
     6public class Brand {
     7
     8    private Integer id; // id 主键
     9    private String brandName; // 品牌名称
    10    private String companyName; // 企业名称
    11    private Integer ordered; // 排序字段
    12    private String description; // 描述信息
    13    private Integer status; // 状态:0:禁用  1:启用
    14
    15    public Integer getId() {
    16        return id;
    17    }
    18
    19    public void setId(Integer id) {
    20        this.id = id;
    21    }
    22
    23    public String getBrandName() {
    24        return brandName;
    25    }
    26
    27    public void setBrandName(String brandName) {
    28        this.brandName = brandName;
    29    }
    30
    31    public String getCompanyName() {
    32        return companyName;
    33    }
    34
    35    public void setCompanyName(String companyName) {
    36        this.companyName = companyName;
    37    }
    38
    39    public Integer getOrdered() {
    40        return ordered;
    41    }
    42
    43    public void setOrdered(Integer ordered) {
    44        this.ordered = ordered;
    45    }
    46
    47    public String getDescription() {
    48        return description;
    49    }
    50
    51    public void setDescription(String description) {
    52        this.description = description;
    53    }
    54
    55    public Integer getStatus() {
    56        return status;
    57    }
    58
    59    public void setStatus(Integer status) {
    60        this.status = status;
    61    }
    62
    63    @Override
    64    public String toString() {
    65        return "Brand{" +
    66                "id=" + id +
    67                ", brandName='" + brandName + '\'' +
    68                ", companyName='" + companyName + '\'' +
    69                ", ordered=" + ordered +
    70                ", description='" + description + '\'' +
    71                ", status=" + status +
    72                '}';
    73    }
    74}
    

实现操作

  1package dao;
  2
  3import pojo.Brand;
  4
  5import com.alibaba.druid.pool.DruidDataSourceFactory;
  6
  7import javax.sql.DataSource;
  8import java.io.FileInputStream;
  9import java.sql.*;
 10import java.util.ArrayList;
 11import java.util.Properties;
 12
 13/**
 14 * 品牌数据的增删改查操作
 15 */
 16public class BrandDAO {
 17
 18    private static DataSource dataSource;
 19
 20    // 获取Connection:
 21    static {
 22        try {
 23            // - 导入jar包 & 定义配置文件
 24            // - 加载配置文件
 25            Properties prop = new Properties();
 26            prop.load(new FileInputStream("demo/src/druid.properties"));
 27            // - 获取连接池对象
 28            dataSource = DruidDataSourceFactory.createDataSource(prop);
 29        } catch (Exception e) {
 30            e.printStackTrace();
 31        }
 32    }
 33
 34    /**
 35     * 查询所有
 36     * 1. SQL: SELECT * FROM tb_brand
 37     * 2. 参数: 不需要
 38     * 3. 结果: ArrayList<Brand>
 39     */
 40    public ArrayList<Brand> selectAll() throws Exception{
 41        // 1. 获取数据库连接Connection
 42        Connection conn = dataSource.getConnection();
 43
 44        // *2. 定义SQL
 45        String sql = "SELECT * FROM tb_brand";
 46
 47        // 3. 获取pstmt对象
 48        PreparedStatement pstmt = conn.prepareStatement(sql);
 49      
 50        // *4. 设置参数
 51      
 52        // 5. 执行SQL
 53        ResultSet rs = pstmt.executeQuery();
 54
 55        // *6. 处理结果: ArrayList<Brand>
 56        Brand brand = null;
 57        ArrayList<Brand> brands = new ArrayList<>();
 58        // - 遍历结果集
 59        while (rs.next()) {
 60            // 1. 获取数据
 61            int id = rs.getInt("id");
 62            String brandName = rs.getString("brand_name");
 63            String companyName = rs.getString("company_name");
 64            int ordered = rs.getInt("ordered");
 65            String description = rs.getString("description");
 66            int status = rs.getInt("status");
 67
 68            // 2. 封装Brand对象
 69            brand = new Brand();
 70            brand.setId(id);
 71            brand.setCompanyName(companyName);
 72            brand.setOrdered(ordered);
 73            brand.setDescription(description);
 74            brand.setStatus(status);
 75
 76            // 3. 装载ArrayList集合
 77            brands.add(brand);
 78        }
 79
 80        // 7. 释放资源
 81        rs.close();
 82        pstmt.close();
 83        conn.close();
 84
 85        // 8. 返回结果
 86        return brands;
 87    }
 88
 89    /**
 90     * 添加
 91     * 1. SQL:
 92         INSERT INTO tb_brand(
 93            brand_name,
 94            company_name,
 95            ordered,
 96            description,
 97            status)
 98         VALUES(?,?,?,?,?)
 99     * 2. 参数: 除了id之外的所有参数信息
100     * 3. 结果: boolean
101     */
102    public boolean add(Brand brand) throws Exception{
103        // 1. 获取数据库连接Connection
104        Connection conn = dataSource.getConnection();
105
106        // *2. 定义SQL
107        String sql = """
108                INSERT INTO tb_brand(
109                    brand_name,
110                    company_name,
111                    ordered,
112                    description,
113                    status)
114                VALUES(?,?,?,?,?)""";
115
116        // 3. 获取pstmt对象
117        PreparedStatement pstmt = conn.prepareStatement(sql);
118
119        // *4. 设置参数
120        pstmt.setString(1, brand.getBrandName());
121        pstmt.setString(2, brand.getCompanyName());
122        pstmt.setInt(3, brand.getOrdered());
123        pstmt.setString(4, brand.getDescription());
124        pstmt.setInt(5, brand.getStatus());
125
126        // 5. 执行SQL
127        int count = pstmt.executeUpdate(); // 返回影响的行数
128
129        // 6. 释放资源
130        pstmt.close();
131        conn.close();
132
133        // 7. 返回结果
134        return count > 0;
135    }
136
137    /**
138     * 修改
139     * 1. SQL:
140         UPDATE tb_brand
141         SET brand_name=?,
142            company_name=?,
143            ordered=?,
144            description=?,
145            status=?
146         WHERE id=?
147     * 2. 参数: 所有
148     * 3. 结果: boolean
149     */
150    public boolean update(Brand brand) throws Exception{
151        // 1. 获取数据库连接Connection
152        Connection conn = dataSource.getConnection();
153
154        // *2. 定义SQL
155        String sql = """
156                UPDATE tb_brand
157                SET brand_name=?,
158                    company_name=?,
159                    ordered=?,
160                    description=?,
161                    status=?
162                WHERE id=?""";
163
164        // 3. 获取pstmt对象
165        PreparedStatement pstmt = conn.prepareStatement(sql);
166
167        // *4. 设置参数
168        pstmt.setString(1, brand.getBrandName());
169        pstmt.setString(2, brand.getCompanyName());
170        pstmt.setInt(3, brand.getOrdered());
171        pstmt.setString(4, brand.getDescription());
172        pstmt.setInt(5, brand.getStatus());
173        pstmt.setInt(6, brand.getId());
174
175        // 5. 执行SQL
176        int count = pstmt.executeUpdate(); // 返回影响的行数
177
178        // 6. 释放资源
179        pstmt.close();
180        conn.close();
181
182        // 8. 返回结果
183        return count > 0;
184    }
185
186    /**
187     * 删除
188     * 1. SQL:DELETE FROM tb_brand WHERE id=?
189     * 2. 参数: id
190     * 3. 结果: boolean
191     */
192    public boolean deleteById(int id) throws Exception{
193        // 1. 获取数据库连接Connection
194        Connection conn = dataSource.getConnection();
195
196        // *2. 定义SQL
197        String sql = "DELETE FROM tb_brand WHERE id=?";
198
199        // 3. 获取pstmt对象
200        PreparedStatement pstmt = conn.prepareStatement(sql);
201
202        // *4. 设置参数
203        pstmt.setInt(1, id);
204
205        // 5. 执行SQL
206        int count = pstmt.executeUpdate(); // 返回影响的行数
207
208        // 6. 释放资源
209        pstmt.close();
210        conn.close();
211
212        // 7. 返回结果
213        return count > 0;
214    }
215}