连接池
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。

使用连接池有哪些好处?
- 减少连接创建时间
创建新的 JDBC 连接仍会有网络和 JDBC 驱动的开销。如果这类连接是“循环”使用的,使用该方式这些花销就可避免。平分。
- 简化的编程模式
当使用连接池时,每一个单独的线程能够像创建了一个自己的 JDBC 连接一样操作,允许用户直接使用JDBC编程技术。
- 受控的资源使用
如果用户不使用连接池,而是每当线程需要时创建一个新的连接,那么用户的应用程序的资源使用会产生非常大的浪费并且可能会导致高负载下的异常发生。

池化思想 池化技术。
面试时,如果面试官问连接池有什么好处、线程池有什么好处?应该怎么答呢?
池化技术(Pooling)是一种常见的资源管理技术,它可以通过预先创建和维护一定数量的资源实例来提高系统的性能和可靠性。池化技术的好处包括:
1. 提高性能:池化技术可以避免频繁地创建和销毁资源实例,从而减少了资源的开销和系统资源的消耗。这样可以提高系统的性能和响应速度。
2. 提高可靠性:池化技术可以监控资源实例的状态,如果资源实例出现异常或超时,池化技术会自动将其标记为无效实例,并重新创建新的实例。这样可以提高系统的可靠性和稳定性。
3. 节约资源:池化技术可以限制资源实例的数量,以避免过多的实例占用系统资源。这样可以节约资源,并提高系统的可扩展性和稳定性。
4. 简化开发:池化技术可以通过配置文件或代码来管理资源实例,使得开发人员可以更加方便地使用资源实例,同时也减少了一些资源管理的复杂性。
自己实现的连接池
通过案例,来理解连接池的实现思想,其余的连接池实现上思路是一致的,实现细节上有差异
连接池。你需要使用的时候,从池子里面(集合)取;使用完毕,放回池子。
代码的核心思想就是:创建一个可以存和取的Connection的集合类对象,关于Connection的获取和放回都通过对这个对象的操作来完成
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.io.FileInputStream;
import java.io.IOException;
public class ConnectionPool {
// 连接池,用于存储数据库连接对象的列表
private static List<Connection> connections;
// 数据库连接相关的配置参数
private static String driverClassName;
private static String url;
private static String username;
private static String password;
// 静态代码块,初始化连接池和数据库连接配置
static {
connections = new ArrayList<>();
Properties properties = new Properties();
try {
// 从配置文件中加载数据库连接参数
properties.load(new FileInputStream("db.properties"));
} catch (IOException e) {
// 如果加载配置文件失败,抛出运行时异常
throw new RuntimeException(e);
}
// 获取数据库驱动类名、URL、用户名和密码
driverClassName = properties.getProperty("driverClass");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
try {
// 加载数据库驱动类
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
// 如果加载驱动类失败,抛出运行时异常
throw new RuntimeException(e);
}
// 初始化连接池,创建5个数据库连接并加入连接池
for (int i = 0; i < 5; i++) {
try {
connections.add(DriverManager.getConnection(url, username, password));
} catch (SQLException e) {
// 如果获取连接失败,抛出运行时异常
throw new RuntimeException(e);
}
}
}
/**
* 获取连接的方法,如果连接池为空,则直接返回null。
*
* @return 连接池对象
*/
public static Connection getConnection() {
if (connections.isEmpty()) {
return null;
}
// 从连接池中取出一个连接对象
return connections.remove(0);
}
/**
* 归还连接的方法,将连接对象放回连接池中。
*
* @param connection 要归还的连接对象
*/
public static void returnConnection(Connection connection) {
connections.add(connection);
}
}
– 实现了哪些功能
– 数据库的连接获取和释放
– 未实现哪些功能
– 自动扩容
– 初始化容量,扩容数量的优化
– 最大连接数量的限制
– 没有超时自动回收功能
市面上已经提供了非常成熟的产品了,我们没有必要自己造轮子。
第三方提供的连接池
如果每一种连接池都有一种自己的获取连接的方式,会导致非常混乱。
// 连接池A提供的获取连接的方法
Connection getConnection(){}
// 连接池B提供的获取连接的方法
Connection aquireConnection(){}
// 连接池C提供的获取连接的方法
Connection get(){}
这样对于Java的使用者来说去使用第三方开源的数据库连接池就可能不太方便,那么Java开发者就在JDBC中定义了一个数据库连接池的接口( javax.sql.Datasource ),其他的数据库连接池的实现都需要去实现这个接口,这就对我们Java开发者来说造成了极大的便利,方便我们去在Java中使用数据库连接池。 => 统一规范
统一规范有什么好处?
举个例子,比如你要出差,出差要带很多东西,比如充电牙刷、剃须刀、手机、耳机、平板、电脑等,假如说每个设备都需要不同的充电器和充电插头,那么其实会很繁琐,如果统一了接口和充电器,那么只需要带一组就可以了,是不是就很方便了呢?
DataSource接口,就是JDBC提供给我们的一个获取连接的接口。 => 统一规范,我们后续的连接池都是有实现DataSource接口的实现类。不同的连接池就是不同的实现类
public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password)
throws SQLException;
}
DBCP
不需要大家把这些背下来。 只要能照着文档,用起来就行。
最早大家都用的连接池。但是在 中间断更了几年,后续出现了一些bug,无人维护,所以索性有一些公司就自己开始开发了。
关于Apache的说明:
1. Apache是世界上最大的开源组织,起源于Apache开源基金会,这个基金的收益用于维护Apache这个开源组织下的开源项目
2. 在Apache开源组织下,管理了若干个开源项目。
这些开源项目(源码是可以直接看到的)可以被所有的公司和个人免费使用
当然,Apache下面的开源项目不是都是有Apache的开发人员开发的,大多的项目来自己其他公司的捐赠。
[官网](https://commons.apache.org/proper/commons-dbcp/index.html)
- 导包。需要两个包:
commons-dbcp、commons-pool

- 配置
username=root
password=123456
url=jdbc:mysql://localhost:3306/test7
driverClassName=com.mysql.cj.jdbc.Driver
# 配置的参数。可以不用在url后面写。以分号分割
connectionProperties=characterEncoding=utf8;useSSL=false;serverTimezone=GMT+8
# 初始化容量。
initialSize=10
- 使用
public class DbcpDataSource1 {
public static void main(String[] args) throws SQLException {
DataSource dataSource = null;
try {
Properties properties = new Properties();
// 获取类加载路径(classpath)下的指定资源,读取为InputStream => 附录
InputStream inputStream = DbcpDataSource1.class.getClassLoader().getResourceAsStream("dbcp.properties");
properties.load(inputStream);
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
Connection connection = dataSource.getConnection();
ExecuteQueryByConnection.executeQuery(connection);
connection.close();
}
}
public class ExecuteQueryByConnection {
public static void executeQuery(Connection connection) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement("select * from account");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
BigDecimal money = resultSet.getBigDecimal("money");
System.out.println(id + " __ " + name + " __ " + money);
}
}
}
之前特别流行的连接池,但是由于中间几年没有更新,所以现在一般都是一些老项目在使用。
- 如果单独导入了一个包(commons-dbcp),报错了,怎么办?遇到这类问题,怎么解决?
ClassNotFoundException
C3P0
dbcp断更后。出来的一个新的数据库连接池。
这里给大家演示一个问题,我们需要导两个包。有的时候忘记了,只导了一个,会出现什么问题?
lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector
- 没导入包会出现这个问题
- 导包了,但是版本不对。
- 拿这个报错去搜索引擎搜索搜索。或者去ChatGPT问。
- 导包

- 配置
需要在src目录下,新建一个配置文件。
方式一:(xml文件)
名字为固定的 c3p0-config.xml
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property
name="jdbcUrl">jdbc:mysql://localhost:3306/test7?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
</default-config>
</c3p0-config>
方式二:(properties文件)
名字为固定的: c3p0.properties
c3p0.driverClass=com.mysql.cj.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test7?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
c3p0.user=root
c3p0.password=123456
- 使用
static DataSource cpds;
static {
// 会自动去类路径下,会找指定的配置文件
cpds = new ComboPooledDataSource();
}
注意:c3p0的配置文件位置,都是写死在C3p0的代码里,所以配置文件的名字和位置都只能是固定的。
Druid
阿里。
- 导包

- 配置(写得配置文件,只要你有办法找到即可。但是尽量不要写绝对路径)
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test7?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username=root
password=123456
- 使用
Properties properties = new Properties();
properties.load(new FileInputStream("druid.properties"));
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
Connection connection = dataSource.getConnection();
HikariCP
SpringBoot的一个数据库连接池。说明比较牛。
- 导包

- 配置
jdbcUrl=jdbc:mysql://localhost:3306/test7?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username=root
password=123456
- 使用
Properties properties = new Properties();
properties.load(new FileInputStream("hikaricp.properties"));
HikariConfig config = new HikariConfig(properties);
DataSource hikariDataSource = new HikariDataSource(config);
Connection connection = hikariDataSource.getConnection();
重点:
池化思想。代码怎么写,不是特别重要,但是还是要练习。
一定一定要能自己的话描述出来。不是背出来。