数据库连接是个耗时操作.对数据库连接的高效管理影响应用程序的性能指标.
数据库连接池正是针对这个问题提出来的.
数据库连接池负责分配,管理和释放数据库连接.它允许应用程序重复使用一个现有的数据路连接,而不需要每次重新建立一个新的连接,利用数据库连接池将明显提升对数据库操作的性能.

数据库连接池技术方案:
1.C3P0
2.DBCP
3.Proxool
4.Tomcat jdbc Oppl
5.BoneCP
6.Druid
7.HikariCP
数据库连接池属于一种池化技术:
常见的有:http访问(httpclient),redis访问(redisPool),线程(线程池)等
新建个空项目



可能是版本原因idea创建空项目总要重启一下
设置下maven和encoding
新建模块


DataSource是JDK里的规范,用来专门放连接的.是一个连接工厂

自定义一个接口

里面需要实现的两个方法是: 其他的父接口的其他方式可以暂时不管


这样基础结构就有了
- package com.pool;
-
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
-
- /**
- * @author hrui
- * @date 2023/9/10 3:06
- */
- public class MyAbstractDataSource implements MyDataSourceInterface{
-
- private String url;
-
- private String driver;
-
- private String username;
-
- private String password;
- //最大的连接数量
- private int poolMaxActiveConnection=10;
-
- //最大空闲连接数
- private int poolMaxIdIeConnection=5;
-
- //当连接都在使用时候,最大检出时间(等待时间),毫秒
- private int poolTimeToWait=20000;
-
- public int getPoolMaxActiveConnection() {
- return poolMaxActiveConnection;
- }
-
- public void setPoolMaxActiveConnection(int poolMaxActiveConnection) {
- this.poolMaxActiveConnection = poolMaxActiveConnection;
- }
-
- public int getPoolMaxIdIeConnection() {
- return poolMaxIdIeConnection;
- }
-
- public void setPoolMaxIdIeConnection(int poolMaxIdIeConnection) {
- this.poolMaxIdIeConnection = poolMaxIdIeConnection;
- }
-
- public int getPoolTimeToWait() {
- return poolTimeToWait;
- }
-
- public void setPoolTimeToWait(int poolTimeToWait) {
- this.poolTimeToWait = poolTimeToWait;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getDriver() {
- return driver;
- }
-
- public void setDriver(String driver) {
- this.driver = driver;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- return getConnection(username,password);
- }
-
- @Override
- public Connection getConnection(String username, String password) throws SQLException {
- return doGetConnection(username,password);
- }
-
- private Connection doGetConnection(String username, String password) throws SQLException {
- Connection connection = DriverManager.getConnection(url, username, password);
- return connection;
- }
- }
上面三个方法,都是获得连接
下面用动态代理方式实现对数据库连接的代理
- package com.pool;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.sql.Connection;
-
- /**
- * 采用动态代理实现对数据库连接的代理
- * @author hrui
- * @date 2023/9/10 3:45
- */
- public class ConnectionProxy implements InvocationHandler {
-
- //真正连接
- private Connection realConnection;
-
- //代理连接
- private Connection proxyConnection;
-
- //数据源对象
- private MyDataSource myDataSource;
-
-
- public ConnectionProxy(Connection realConnection, MyDataSource myDataSource) {
- //初始化真实连接和数据源
- this.realConnection = realConnection;
- this.myDataSource = myDataSource;
-
- //初始化代理连接...需要一个代理对象 JDK动态代理
- this.proxyConnection= (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
- new Class>[]{Connection.class},
- this);
-
- }
-
- public Connection getRealConnection() {
- return realConnection;
- }
-
- public void setRealConnection(Connection realConnection) {
- this.realConnection = realConnection;
- }
-
- public Connection getProxyConnection() {
- return proxyConnection;
- }
-
- public void setProxyConnection(Connection proxyConnection) {
- this.proxyConnection = proxyConnection;
- }
-
- public MyDataSource getMyDataSource() {
- return myDataSource;
- }
-
- public void setMyDataSource(MyDataSource myDataSource) {
- this.myDataSource = myDataSource;
- }
-
- /**
- * 当调用Connection对象里面的任何方法时,该方法会进行拦截
- * 主要目的为了拦截Connection的close方法,当关闭时进行拦截,将Connection对象放入连接池中
- * 其他方法无需拦截
- * @param proxy
- * @param method
- * @param args
- * @return
- * @throws Throwable
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- //获取当前调用了Connection对象的什么方法
- String methodName=method.getName();
- if(methodName.equals("close")){
- //TODO 把连接放入连接池
-
- return null;
- }else{
- //其他方法
- return method.invoke(realConnection, args);
- }
-
- }
- }
-
- }
-
下面写个类继承MyAbstractDataSource 在里面放入连接池
- package com.pool;
-
- import java.sql.Connection;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * 数据源连接池
- * @author hrui
- * @date 2023/9/10 4:15
- */
- public class MyDataSource extends MyAbstractDataSource{
-
- //空闲连接
- private final List<ConnectionProxy> idleConnections=new ArrayList<>();
-
- //激活的连接池
- private final List<ConnectionProxy> activeConnections=new ArrayList<>();
-
- //下面三个可以抽取放到父类抽象类中,由用户配置
- //最大的连接数量
- //private int poolMaxActiveConnection=10;
-
- //最大空闲连接数
- //private int poolMaxIdIeConnection=5;
-
- //当连接都在使用时候,最大检出时间(等待时间),毫秒
- //private int poolTimeToWait=20000;
-
- //用于同步监视器对象
- private final Object monitor=new Object();
-
- //用于同步监视器对象(关闭)
- //private final Object watch=new Object();
-
- /**
- * 重写:用于获取代理连接
- * @return
- * @throws SQLException
- */
- @Override
- public Connection getConnection() throws SQLException {
- ConnectionProxy connectionProxy=getConnectionProxy(super.getUsername(),super.getPassword());
- //返回代理连接
- return super.getConnection();
- }
-
- /**
- * 获取代理连接
- * @param username
- * @param password
- * @return
- */
- private ConnectionProxy getConnectionProxy(String username,String password) throws SQLException {
- //TODO
- //是否需要等待
- boolean wait=false;
- ConnectionProxy connectionProxy=null;
- //刚开始没有连接
- while(connectionProxy==null){
- synchronized (monitor){
- //看连接池有没有空闲连接,如果不为空,直接获取连接
- if(!idleConnections.isEmpty()){
- connectionProxy=idleConnections.remove(0);
- //如果是空的
- }else{
- //没有空闲连接,那么需要获取新的连接(创建连接)
- //这里先判断最大连接数是不是小于配置数量 10
- if(activeConnections.size()<supper.getPoolMaxActiveConnection()){
- //创建新连接 需要传入真实连接
- connectionProxy=new ConnectionProxy(super.getConnection(),this);
- }
- //否则需要等待20秒 上面定义了poolTimeToWait=20000
-
- }
- }
-
- if(!wait){
- wait=true;
- }
-
- if(connectionProxy==null){
- try {
- monitor.wait(supper.getPoolTimeToWait());
- } catch (InterruptedException e) {
- e.printStackTrace();
- //万一等待被线程打断,退出一下
- break;
- }
- }
-
- }
- if(connectionProxy!=null){
- //连接对象不是空,说明已经拿到连接了,放入容器
- activeConnections.add(connectionProxy);
- }
-
- return connectionProxy;
- }
-
- //用于关连接
- //不是把连接关系,而是还给连接池
- public void closeConnection(ConnectionProxy connectionProxy){
- synchronized (monitor){
- //最大连接(激活连接)里删除
- activeConnections.remove(connectionProxy);
-
- //如果空闲连接<定义的数量则放入空闲连接
- if(idleConnections.size()<supper.getPoolMaxIdIeConnection()){
- idleConnections.add(connectionProxy);
- }
- //通知一下,唤醒上面哪个等待获取连接的线程
- monitor.notify();
- }
- }
- }
那么代理对象中把连接还给连接池的方法也有了

就是当所有连接用完了,等待20秒的逻辑没写
下面测试自己写的连接池
新建模块 引入依赖


不想玩了