连接池的基本原理
在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。如外部使用者可通过 getConnection 方法获取数据库连接,使用完毕后再通过releaseConnection 方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
连接池同时负责定期检查连接的可用性,并保证最大空闲时间。
连接池的作用
- 资源重用
- 更快的系统响应速度
- 新的资源分配手段
- 统一的连接管理,避免数据库连接泄露
连接池
在一次查询操作中,60%以上的时间是用于创建数据库连接上了,为了提高执行效率,可以考虑减少创建数据库连接的时间。
因为没有办法降低一次创建连接所用时长,所以考虑采用共享的方式降低平均使用成本。典型应用有线程池。数据库连接池的基本思想是:为数据库连接建立一个“缓冲池”,预先在池中放入一定数量的数据库连接管道,需要时,从池子中取出管道进行使用,操作完毕后,在将管道放入池子中,从而避免了频繁的向数据库申请资源,释放资源带来的性能损耗。同时一般会有一个守护线程定期检查空闲连接是否可用,如果连接已经不稳定则释放连接对象.
编码简单实现
package com.user.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class JdbcUtil {
///使用单例保证连接池只有一个
private static JdbcUtil ju = new JdbcUtil();
public static JdbcUtil getInstance() {return ju;}
private static List<Connection> pool;; //具体的连接池容器,集合的最佳选择可以考虑使用阻塞队列
private static final int MAX_SIZE = 10;; //连接池的相关参数,实际上还有其他的数据,例如最小连接池、最大空闲时间等
// 实际上还应该有守护线程定期检查连接对象的可用性,如果连接对象不可用则需要释放连接
private JdbcUtil() {}
static {
//使用静态块,所以没有线程安全问题
pool = Collections.synchronizedList(new ArrayList<>());
try {
Class.forName("com.mysql.cj.jdbc.Driver");
for (int i = 0; i < 3; i++) {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/studentsystem?serverTimezone=UTC",
"root", "123456");
pool.add(conn);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Connection getConnection() throws SQLException {
Connection conn = null;
if (pool.size() > 0)
conn = pool.remove(pool.size() - 1);
else
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/studentsystem?serverTimezone=UTC", "root",
"123456");
return conn;
}
public void realseConnection(Connection conn) throws SQLException {
if (conn != null)
if (pool.size() < MAX_SIZE)
pool.add(conn);
else
conn.close();
}
public void close(Connection conn, PreparedStatement ps, ResultSet rs) throws SQLException {
try {
if (rs != null)
rs.close();
} finally {
try {
if (ps != null)
ps.close();
} finally {
if (conn != null)
realseConnection(conn);
}
}
}
public static PreparedStatement createPreparedStatement(Connection conn, String sql, Object... objects)
throws SQLException {
PreparedStatement ps = conn.prepareStatement(sql);
if (objects != null && objects.length > 0)
for (int i = 0; i < objects.length; i++)
ps.setObject(i + 1, objects[i]);
return ps;
}
public int executeUpdate(Connection conn, String sql, Object... objects) throws SQLException {
PreparedStatement ps = createPreparedStatement(conn, sql, objects);
return ps.executeUpdate();
}
public ResultSet executeQuery(Connection conn, String sql, Object... objects) throws SQLException {
PreparedStatement ps = createPreparedStatement(conn, sql, objects);
return ps.executeQuery();
}
}