数据库连接池基本介绍
文章目录
1. 基本概念
数据库连接池的本质上是一个容器(集合),存放数据库连接的容器,当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完后,会将连接对象归还给容器。百度百科介绍
使用数据库连接池可以:节约资源、提高访问效率。
2. 数据源标准接口 —— javax.sql.DataSource
DataSource 是一个连接物理数据源的工厂,用于连接到此 DataSource 对象表示的物理数据源 。
除了用 DriverManager 对象获取数据库连接外,DataSource 对象是获得数据库连接的首选方法。
2.1 DataSource 的三种实现类型
实现类型 | 描述 |
---|---|
基本实现 | 创建一个标准的 Connection 对象。 |
连接池实现 | 创建一个 Connection 对象,该对象将自动参与连接池。 |
分布式事务实现 | 创建一个 Connection 可用于分布式事务的对象 |
2.2 部分相关的方法及描述
方法名 | 描述 |
---|---|
Connection getConnection() | 尝试与数据源建立连接,返回连接对象。 |
Connection getConnection(String username, String password) | 尝试与数据源建立连接,返回连接对象。 |
void close() | 归还该 Connection 对象的数据库 和 JDBC资源。 |
PrintWriter getLogWriter() | 检索此 DataSource 对象的日志编写器。 |
2.3 C3P0 数据库连接池
C3P0是一个开源的JDBC连接池,目前使用它的开源项目有Hibernate、Spring等。
2.3.1 使用步骤
-
导入jar包
- C3P0 jar包下载地址
- mysql-connector-java-8.0.17.jar : 注意与自己装的数据库版本对应。
- c3p0-0.9.5.2.jar
- mchange-commons-java-0.2.11.jar
-
定义配置文件
- 命名固定:c3p0.properties 或 c3p0-config.xml
- 放置路径:src 路径下
- 配置内容可以查看百度百科,后文会简单介绍几个。
-
创建核心对象
- ComboPooledDataSource
-
获取连接对象
- 方法:getConnection
-
获取连接对象后就可以进行其他JDBC相关的操作了,这里不再演示。
2.3.2 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置 -->
<default-config>
<!--连接参数,数据库相关参数配置-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<!--连接池参数-->
<!--初始化申请的连接数量-->
<property name="initialPoolSize">10</property>
<!--最大的连接池数量-->
<property name="maxPoolSize">10</property>
<!--超时时间,单位为毫秒-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 命名配置 -->
<named-config name="otherc3p0">
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">3000</property>
</named-config>
</c3p0-config>
注意数据库参数配置:
- mysql 5.0 的驱动路径为:com.mysql.jdbc.Driver
- MySQL 8.0 的驱动路径为:com.mysql.cj.jdbc.Driver
- MySQL 8.0 之后必须加 : ?serverTimezone=UTC
- 如:jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC
- 否则会报错时区错误。
2.3.3 Java代码基本演示:获取连接对象并打印到控制台
package com.base.datasource.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0Demo1 {
public static void main(String[] args) throws SQLException {
//1.1 获取DataSource,使用默认配置
// DataSource ds = new ComboPooledDataSource();
//1.2 获取连接对象
// Connection conn = ds.getConnection();
//3. 打印
// System.out.println(conn);
// 2.1 获取DataSource,使用指定名称的配置
DataSource ds = new ComboPooledDataSource("otherc3p0");
for (int i=1;i<=10;i++){
// 2.2 获取连接对象
Connection conn = ds.getConnection();
// 2.2 打印
System.out.println(i +" : "+ conn);
if (i == 5){
conn.close();
}
}
}
}
运行结果:
1 : com.mchange.v2.c3p0.impl.NewProxyConnection@6a5fc7f7 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@3b6eb2ec]
2 : com.mchange.v2.c3p0.impl.NewProxyConnection@6e8dacdf [wrapping: com.mysql.cj.jdbc.ConnectionImpl@7a79be86]
3 : com.mchange.v2.c3p0.impl.NewProxyConnection@b684286 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@880ec60]
4 : com.mchange.v2.c3p0.impl.NewProxyConnection@7f63425a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@36d64342]
5 : com.mchange.v2.c3p0.impl.NewProxyConnection@511baa65 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@340f438e]
6 : com.mchange.v2.c3p0.impl.NewProxyConnection@19dfb72a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@17c68925]
7 : com.mchange.v2.c3p0.impl.NewProxyConnection@3d24753a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@340f438e]
8 : com.mchange.v2.c3p0.impl.NewProxyConnection@7a0ac6e3 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@71be98f5]
9 : com.mchange.v2.c3p0.impl.NewProxyConnection@17f6480 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@2d6e8792]
Exception in thread "main" java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
注意:
- 配置文件里面配置的初始化创建的连接池对象是5个,最大连接池对象是8个。
- 代码展示中一共创建了10个连接对象,但是只成功创建了9个连接对象,还剩一个出现超时异常(3秒左右)
- 能够创建9个连接对象的原因是,我们归还了第五个连接池对象,这个连接池对象被第七个连接对象获取了,通过后面的哈希值可以判断出这两个连接池对象是同一个。
- 最后一个连接对象没有创建成功的原因是,连接对象已经达到我们设定的最大连接数量 8个,如果没有归还的话,其他连接对象就不能被创建出来。
2.4 Druid 数据库连接池
Apache Druid 是一个分布式内存实时分析系统,用于解决如何在大规模数据集下进行快速的、交互式的查询和分析。
2.4.1 使用步骤
-
导入jar包
- maven仓库下载地址
- mysql-connector-java-8.0.17.jar
- druid-1.1.9.jar
-
配置文件
- 命名不固定。
- 是 properties 形式的。
- 可以放在任意路径下。
-
加载配置文件
- 类:Properties
- 方法:
- getClassLoader()
- getResourceAsStream()
- load()
-
获取数据库连接池对象
- 通过工厂类获取:DruidDataSourceFactory
-
获取连接
- 获取方法:getConnection()
2.4.2 配置文件
因为命名没有限制,这里取名为:druid.properties,内容如下:
# 数据库连接参数信息
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
2.4.3 Java代码基本演示:获取并打印连接对象
package com.base.datasource.druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
* Druid连接池基本演示
*/
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1. 加载配置文件,类加载器
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2. 获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//3. 获取连接对象
Connection conn = ds.getConnection();
//4. 打印连接对象
System.out.println(conn);
}
}
运行结果:
com.mysql.cj.jdbc.ConnectionImpl@62e136d3
2.4.4 Druid 工具类编写
- 编写工具类 JDBCUtils
package com.base.utils;
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. 定义成员变量 DataSource
private static DataSource ds;
static {
try {
//1. 加载配置文件
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2. 获取 DataSource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return Connection 对象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 释放资源
* @param stmt Statement对象
* @param conn Connection对象
*/
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();
}
}
}
/**
* 释放资源方法重载
* @param rs ResultSet对象
* @param stmt Statement 对象
* @param conn Connection 对象
*/
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 获取连接池对象
* @return ds 连接池对象
*/
public static DataSource getDataSource() {
return ds;
}
}
- 使用工具类创建连接,并执行简单数据库操作。
package com.base.datasource.druid;
import com.base.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 使用JDBC工具类
* 完成添加操作,给account添加一条记录。
*/
public class DruidDemo2 {
public static void main(String[] args) throws Exception {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1. 获取连接
conn = JDBCUtils.getConnection();
//2. 定义 SQL
String sql = "insert into account values(null,?,?)";
//3. 获取 pstmt 对象
pstmt = conn.prepareStatement(sql);
//4. 给占位符(?)赋值
pstmt.setString(1, "张三");
pstmt.setDouble(2, 2000);
//5. 执行 sql
int count = pstmt.executeUpdate();
System.out.println(count);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 释放资源
JDBCUtils.close(pstmt, conn);
}
}
}
运行结果:
十月 31, 2019 4:24:03 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1
注意:没有数据库和对应的表需要提前创建一个,下面提供SQL代码。
-- 创建数据库
CREATE DATABASE IF NOT EXISTS demo_test CHARACTER SET utf8 ;
USE demo_test;
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) UNIQUE NOT NULL,
money VARCHAR(32) NOT NULL
);
时间:2019年10月31日15:59:13