連接池的作用就是爲了提高性能。
連接池的作用:連接池是將已經創建好的連接保存在池中,當有請求來時,直接使用已經創建好的連接對數據庫進行訪問。這樣省略了創建連接和銷燬連接的過程。這樣性能上得到了提高。
基本原理是這樣的:
- 建立數據庫連接池對象(服務器啓動)。
- 按照事先指定的參數創建初始數量的數據庫連接(即:空閒連接數)。
- 對於一個數據庫訪問請求,直接從連接池中得到一個連接。如果數據庫連接池對象中沒有空閒的連接,且連接數沒有達到最大(即:最大活躍連接數),創建一個新的數據庫連接。
- 存取數據庫。
- 關閉數據庫,釋放所有數據庫連接(此時的關閉數據庫連接,並非真正關閉,而是將其放入空閒隊列中。如實際空閒連接數大於初始空閒連接數則釋放連接)。
- 釋放數據庫連接池對象(服務器停止、維護期間,釋放數據庫連接池對象,並釋放所有連接)。
連接池的概念和爲什麼要使用連接池?
連接池放了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'}
好像沒有什麼問題,歡迎夥伴們交流討論,等你哦~