参考文章
Java中的池化思想
面试官:为什么数据库连接很消耗资源,资源都消耗在哪里?
池化思想是什么?连接池是什么?
在Java中,池化思想是一种通过创建和管理可重复使用的对象池来提高性能和资源利用率的编程思想。它的核心概念是在需要时从池中获取对象,而不是每次都创建新的对象,使用完毕后将对象返回到池中,以供其他代码复用。
连接池主要指的是数据库连接池,它可以预先申请一定数量数据库连接,需要的时候从连接池中直接取,用完了放回去,供给其他线程连接数据库使用;
为什么要使用连接池?(作用)
以mysql数据库为例,不使用jdbc创建mysql连接的过程和代码如下:
- mysql驱动类加载
- 创建连接对象connection
- 创建执行对象statement
- 编写sql,执行sql,获取执行结果集对象resultSet,业务处理结果集
- 关闭执行结果集对象resultSet,关闭执行对象statement,关闭连接对象connection(关闭顺序不能错!!!)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1. mysql驱动加载
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 创建连接
Connection connection = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/qcby?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false",
"root", "980708");
// 3. 创建执行对象
Statement statement = connection.createStatement();
// 4. 编写sql,执行sql,获取执行结果集,遍历结果集
ResultSet rs = statement.executeQuery("select * from commodity");
while (rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String countNum = rs.getString("countNum");
String price = rs.getString("price");
String userId = rs.getString("user_id");
String img = rs.getString("img");
System.out.println("id=" + id + ",name=" + name + ",countNum=" + countNum + ",price=" + price + ",userId="
+ userId + ",img=" + img);
}
// 5. 关闭资源
rs.close();
statement.close();
connection.close();
}
}
每执行一次sql语句,都要走一遍这样的流程,除去第四步,剩下的步骤任何sql执行过程都相同!
mysql连接的创建和销毁是非常耗时的,因为mysql连接大部分时候都是TCP/IP的网络请求,三次握手四次挥手一步都不能少!TCP/IP请求的关闭虽然只需要java服务器发送一次握手,但是也需要经过mysql服务器的四次挥手才能关闭成功!也就是说每完成一次连接的建立,数据在客户端和服务器之间需要至少往返7次;每完成一次连接的关闭,数据在客户端和服务器之间需要至少往返5次!
加起来就是12次往返
这是从大佬博客当中截取的mysql数据库连接耗时计算:
PS:这里为什么说是大部分,因为java服务和mysql服务有可能运行在同一台主机上,这样就是进程间通信;但是大部分时候,尤其是实际项目,Java服务和mysql服务在高并发的场景下的内存占用都很高,不可能部署在同一台主机,此时就需要用到TCP/IP进行远程调用建立连接;
所以我们需要使用连接池。
池化思想的好处
1. 提高性能
池化可以避免频繁地创建和销毁对象、连接或线程,从而减少了系统的开销。通过重复使用已存在的资源,可以节省创建和初始化的时间,提高整体的执行效率和响应速度。
2. 提高资源利用率
池化可以更好地管理和控制资源的使用。通过限制可用的资源数量,可以避免资源的过度消耗和浪费,从而提高系统的资源利用率。
3. 提高系统可伸缩性
通过使用池化,系统可以更好地处理并发请求。由于资源已经预先创建,可以快速分配给请求,并在处理完毕后返回池中,从而减少了资源的竞争和等待时间,提高了系统的并发能力和可伸缩性。
4. 代码简化
池化使得资源的获取和释放变得简单,代码更加清晰。不需要在每个使用时都创建和销毁资源的代码逻辑,而是通过获取和释放资源来实现复用,减少了重复代码的编写。
BufferedInputStream读取.properties文件+JDBC连接池的使用实战
public class JdbcUtils2 {
// 连接池对象
private static DataSource DATA_SOURCE;
static{
// 加载属性文件
Properties pro = new Properties();
InputStream inputStream = JdbcUtils2.class.getResourceAsStream("/druid.properties");
try {
// 加载属性文件
pro.load(inputStream);
// 创建连接池对象
DATA_SOURCE = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从连接池中获取连接,返回。
* @return
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = DATA_SOURCE.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭资源
* @param conn
* @param stmt
* @param rs
*/
public static void close(Connection conn, Statement stmt, ResultSet rs){
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();
}
}
}
/**
* 关闭资源
* @param conn
* @param stmt
*/
public static void close(Connection conn, Statement stmt){
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
durid.properties文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbcdemo
username=root
password=980708
initialSize=5 # 初始化连接数
maxActive=10 # 最大活跃连接数
maxWait=3000 # 最长等待时间
maxIdle=6 # 最大等待连接中的数量,设 0 为没有限制
minIdle=3 # 最小等待连接中的数量