手写数据库连接池
几个概念:
1、初始化连接数,比如存在5个Connection
2、最大连接数,比如最大10个Connection
3、空闲池,存放当钱没有被使用的connection
4、活动池,存放当前正在使用的connection
5、执行完业务逻辑后,进行连接的释放,即放入空闲池
6、数据库本身也对连接数有一定的限制,比如MySql同时允许最大连接100个
初始化时生成的默认连接数放置在空闲连接池中。
容器必须是线程安全的,并发操作连接对象。(从空闲池到活动池)
注意几个点:
当connection使用完成之后,需要重新放置到空闲池里面。
空闲池和活动池必须是线程安全的
获取连接时,当检测到活动池中的connection数量已经超过最大连接数,则进行重新获取(递归调用)。
从空闲连接池中获取连接实例后,需要把该实例添加至活动空闲池中,同时删除空闲池中的记录
配置类:手动添加一下setter和getter方法
package pool; /** * Created by 156 on 2019/3/28. * * 需要 MySql-connect 5.x版本 */ public class DbBean { /* 链接属性 */ private String driverName = "com.mysql.jdbc.Driver"; private String url = "jdbc:mysql://localhost:3306/spring5"; private String userName = "root" private String password = "123456"; private int minConnections = 1; // 空闲池,最小连接 private int maxConnections = 10; // 空闲池,最大连接数 private int initConnections = 5;// 初始化连接数 }
连接池
package pool; import java.sql.Connection; import java.sql.DriverManager; import java.util.List; import java.util.Vector; /** * Created by 156 on 2019/3/28. */ public class ConnectionPool implements IConnectionPool { public void setFreeConnection(List<Connection> freeConnection) { this.freeConnection = freeConnection; } // 空闲线程集合 private List<Connection> freeConnection = new Vector<Connection>(); // 活动线程集合 private List<Connection> activeConnection = new Vector<Connection>(); private DbBean dbBean; public ConnectionPool(DbBean dbBean) throws Exception { this.dbBean = dbBean; init(); } public void init() throws Exception { // 根据初始化的连接数,进行创建Connection实例 for (int i = 0; i < dbBean.getInitConnections(); i++) { Connection instance = createConn(); if (null != instance ) { freeConnection.add(instance); // 将创建的实例添加至空闲池中 } } } // 创建新的Connection private Connection createConn() { try { if (null == dbBean) { return null; } Class.forName(dbBean.getDriverName()); Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(), dbBean.getPassword()); return connection; } catch (Exception e) { return null; } } /*** * 获取connecton * 1、首先判断空闲池中是否还有connection实例 * 2、当空闲池线中没有connection实例时, * 判断当前活动线程池中存在的connection数目是否大于最大connection数目 * * * @return */ public Connection getConnection() { Connection connection = null; // 说明空闲池中还有未使用的connection实例,直接返回 // 不需要记录该connectio获取的动作 if (freeConnection.size()>0) { // 1、备份需要返回的connection Connection reConn = freeConnection.get(0); // 判断当前连接是否可用 if(!isAvailable(reConn)){ return null; } // 2、从空闲连接池中移除 freeConnection.remove(0); // 3、添加至活动连接池中 activeConnection.add(reConn); return reConn; // 返回一个connection实例 } // 当前活动connection实例数目小于配置的最大数目时,进行新实例的创建 // 在返回一个Connection实例的同时,同时记录一下新生成的connection if ( activeConnection.size()<dbBean.getMaxConnections()) { // 1、重新生成连接 Connection newC = createConn(); // 判断当前连接是否可用 if(!isAvailable(newC)){ return null; } // 2、记录一下新生成的connection activeConnection.add(newC); return createConn(); } // 当前活动的connection实例已经大于最大数目,则进行重新获取 if(activeConnection.size()>dbBean.getMaxConnections()) { return getConnection(); } return null; } public void releaseConnection(Connection connection) { try { if (connection == null) { return; } if (isAvailable(connection)) { // 判断空闲线程数是否大于最大线程数 if (freeConnection.size() < dbBean.getMaxConnections()) { freeConnection.add(connection); } } } catch (Exception e) { } } // 判断连接是否可用 public boolean isAvailable(Connection connection) { try { if (connection == null || connection.isClosed()) { return false; } } catch (Exception e) { // TODO: handle exception } return true; } }
测试
@Test public void test() throws Exception { ConnectionPool connectionPool = new ConnectionPool(new DbBean()); for (int i=1;i<=11;i++){ System.out.println(i+"===>"+connectionPool.getConnection()); } }