连接池的作用就是为了提高性能。
连接池的作用:连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。这样省略了创建连接和销毁连接的过程。这样性能上得到了提高。
基本原理是这样的:
- 建立数据库连接池对象(服务器启动)。
- 按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
- 对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。
- 存取数据库。
- 关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。
- 释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。
连接池的概念和为什么要使用连接池?
连接池放了N个Connection对象,本质上放在内存当中,在内存中划出一块缓存对象,应用程序每次从池里获得Connection对象,而不是直接从数据里获得,这样不占用服务器的内存资源。
如果不使用连接池会出现的情况:
- 占用服务器的内存资源
- 导致服务器的速度非常慢
既然,大家都了解了连接池的好处,那么我就动手写个固定大小的连接池,以方便伙伴们学习和交流。话不多说,直接上代码,走着~
package com.smallfan.connectionpool;
import com.smallfan.TestVisiblity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;
/**
* @PACKAGE_NAME: com.smallfan.connectionpool
* @NAME: ConnectionPool
* @USER: dell
* @DATE: 2020/5/28
* @PROJECT_NAME: aboutthread
* 模拟实现固定大小的数据库连接池
*/
public class TestPool{
public static void main(String[] args) {
//初始化连接池
ConnectionPool pool = new ConnectionPool(2);
for (int i = 0; i < 5; i++) {//创建5个线程争抢连接池
new Thread(()->{
Connection apply = pool.apply();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.free(apply);
}).start();
}
}
}
class ConnectionPool {
static Logger logger = LoggerFactory.getLogger(ConnectionPool.class);
//初始化连接池池大小
private final int poolSize;
//使用数组存储连接对象
private Connection[] connections;
//使用原子数组记录连接池状态 0:空闲 1:繁忙
private AtomicIntegerArray status;
//初始化
public ConnectionPool(int poolSize) {
this.poolSize = poolSize;
this.connections = new Connection[poolSize];
this.status = new AtomicIntegerArray(new int[poolSize]);
for (int i = 0; i < poolSize; i++) {//初始化数据库连接
connections[i] = new TestConnection("连接"+i);
}
}
//申请连接
public Connection apply(){
while (true){
for (int i = 0; i < poolSize; i++) {
if(status.get(i) == 0){//是否存在空闲的连接
if(status.compareAndSet(i,0,1)){//更新空闲连接为繁忙状态,保证原子操作并返回true
logger.info("获取连接 {}",connections[i]);
return connections[i];
}
}
}
//若都是繁忙状态,阻塞
synchronized (this){
try {
logger.info("等待连接");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//释放连接
public void free(Connection connection){
for (int i = 0; i < poolSize; i++) {
if (connections[i] == connection){
logger.info("释放连接{}",connections[i]);
status.set(i,0);
synchronized (this){
this.notifyAll();
}
break;
}
}
}
}
//模拟实现Connection接口
class TestConnection implements Connection{
String name;
public TestConnection(String name) {
this.name = name;
}
@Override
public String toString() {
return "TestConnection{" +
"name='" + name + '\'' +
'}';
}
public Statement createStatement() throws SQLException {
return null;
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
return null;
}
public CallableStatement prepareCall(String sql) throws SQLException {
return null;
}
public String nativeSQL(String sql) throws SQLException {
return null;
}
public void setAutoCommit(boolean autoCommit) throws SQLException {
}
public boolean getAutoCommit() throws SQLException {
return false;
}
public void commit() throws SQLException {
}
public void rollback() throws SQLException {
}
public void close() throws SQLException {
}
public boolean isClosed() throws SQLException {
return false;
}
public DatabaseMetaData getMetaData() throws SQLException {
return null;
}
public void setReadOnly(boolean readOnly) throws SQLException {
}
public boolean isReadOnly() throws SQLException {
return false;
}
public void setCatalog(String catalog) throws SQLException {
}
public String getCatalog() throws SQLException {
return null;
}
public void setTransactionIsolation(int level) throws SQLException {
}
public int getTransactionIsolation() throws SQLException {
return 0;
}
public SQLWarning getWarnings() throws SQLException {
return null;
}
public void clearWarnings() throws SQLException {
}
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
public Map<String, Class<?>> getTypeMap() throws SQLException {
return null;
}
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
}
public void setHoldability(int holdability) throws SQLException {
}
public int getHoldability() throws SQLException {
return 0;
}
public Savepoint setSavepoint() throws SQLException {
return null;
}
public Savepoint setSavepoint(String name) throws SQLException {
return null;
}
public void rollback(Savepoint savepoint) throws SQLException {
}
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
}
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return null;
}
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return null;
}
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return null;
}
public Clob createClob() throws SQLException {
return null;
}
public Blob createBlob() throws SQLException {
return null;
}
public NClob createNClob() throws SQLException {
return null;
}
public SQLXML createSQLXML() throws SQLException {
return null;
}
public boolean isValid(int timeout) throws SQLException {
return false;
}
public void setClientInfo(String name, String value) throws SQLClientInfoException {
}
public void setClientInfo(Properties properties) throws SQLClientInfoException {
}
public String getClientInfo(String name) throws SQLException {
return null;
}
public Properties getClientInfo() throws SQLException {
return null;
}
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return null;
}
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return null;
}
public void setSchema(String schema) throws SQLException {
}
public String getSchema() throws SQLException {
return null;
}
public void abort(Executor executor) throws SQLException {
}
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
}
public int getNetworkTimeout() throws SQLException {
return 0;
}
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
查看输出结果:
2020-05-28 23:37:18:687 [Thread-2] 等待连接
2020-05-28 23:37:18:689 [Thread-0] 获取连接 TestConnection{name='连接1'}
2020-05-28 23:37:18:689 [Thread-1] 获取连接 TestConnection{name='连接0'}
2020-05-28 23:37:18:716 [Thread-4] 等待连接
2020-05-28 23:37:18:716 [Thread-3] 等待连接
2020-05-28 23:37:19:717 [Thread-1] 释放连接TestConnection{name='连接0'}
2020-05-28 23:37:19:717 [Thread-0] 释放连接TestConnection{name='连接1'}
2020-05-28 23:37:19:718 [Thread-3] 获取连接 TestConnection{name='连接0'}
2020-05-28 23:37:19:718 [Thread-2] 等待连接
2020-05-28 23:37:19:718 [Thread-4] 获取连接 TestConnection{name='连接1'}
2020-05-28 23:37:20:732 [Thread-3] 释放连接TestConnection{name='连接0'}
2020-05-28 23:37:20:732 [Thread-2] 获取连接 TestConnection{name='连接0'}
2020-05-28 23:37:20:732 [Thread-4] 释放连接TestConnection{name='连接1'}
2020-05-28 23:37:21:732 [Thread-2] 释放连接TestConnection{name='连接0'}
好像没有什么问题,欢迎伙伴们交流讨论,等你哦~