使用Apache Commons Pool實現資料庫連線池
阿新 • • 發佈:2019-02-19
通過組合Apache Commons Pool提供的GenericObjectPool實現資料庫連線池
import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import java.io.Closeable; import java.sql.Connection; public class DbPool implements Closeable { private GenericObjectPool<Connection> internalPool; public DbPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory factory){ if (this.internalPool != null) { try { closeInternalPool(); } catch (Exception e) { } } this.internalPool = new GenericObjectPool(factory, poolConfig); } // 獲取連線 public Connection getConnection(){ Connection connection = null; try { connection = internalPool.borrowObject(); } catch (Exception e) { throw new RuntimeException("Could not get connection from the pool", e); } return connection; } // 返還連線 public void returnConnection(Connection connection){ internalPool.returnObject(connection); } @Override public void close(){ this.closeInternalPool(); } private void closeInternalPool() { try { internalPool.close(); } catch (Exception e) { throw new RuntimeException("Could not destroy the pool", e); } } }
borrowObject的實現方式如下
public class GenericObjectPool<T> extends BaseGenericObjectPool<T> implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> { private final PooledObjectFactory<T> factory; private final LinkedBlockingDeque<PooledObject<T>> idleObjects; public T borrowObject(final long borrowMaxWaitMillis) throws Exception { ...... p = idleObjects.pollFirst(); if (p == null) { p = create(); if (p != null) { create = true; } } ...... return p.getObject(); } private PooledObject<T> create() throws Exception { ...... p = factory.makeObject(); ...... return p; } }
物件池中並不直接儲存最終使用的物件例項,而是使用PooledObject對最終使用的物件例項進行了一層封裝
通過封裝物件給物件例項增加了諸如狀態、時間等一系列屬性
DbConnectionFactory用來定義物件池中的物件例項的生命週期方法(建立、銷燬等),通過繼承Apache Commons Pool提供的BasePooledObjectFactory實現
import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import java.sql.Connection; import java.sql.DriverManager; public class DbConnectionFactory extends BasePooledObjectFactory<Connection> { private DbConfig dbConfig; public DbConnectionFactory(DbConfig dbConfig){ super(); this.dbConfig = dbConfig; } // 建立新的資料庫連線 public Connection create() throws Exception { Connection connection = DriverManager.getConnection(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword()); return connection; } // 使用PooledObject對資料庫連線進行包裝 public PooledObject<Connection> wrap(Connection connection) { return new DefaultPooledObject(connection); } // 由於validateObject失敗或其它什麼原因,物件例項從物件池中移除時呼叫 // 不能保證物件例項被移除時所處的狀態 public void destroyObject(PooledObject<Connection> pooledConnection) throws Exception { Connection connection = pooledConnection.getObject(); connection.close(); } // 僅能被active狀態的物件例項呼叫 // 從物件池獲取物件例項,在物件池返回該物件例項前,呼叫該方法校驗其狀態 // 物件例項歸還給物件池時,在呼叫passivateObject方法前,使用該方法校驗其狀態 public boolean validateObject(PooledObject<Connection> pooledConnection) { Connection connection = pooledConnection.getObject(); try { if (connection.isValid(1)) return true; else return false; }catch(Exception e){ return false; } } // 物件例項在歸還給物件池時呼叫了passivateObject方法,通過物件池再次取到該物件例項 // 在物件池返回該物件例項前,需要呼叫該方法 public void activateObject(PooledObject<Connection> pooledConnection) throws Exception { } // 物件例項歸還給物件池時呼叫 public void passivateObject(PooledObject<Connection> pooledConnection) throws Exception { } }
DbConfig用來儲存資料庫配置
public class DbConfig {
private String url;
private String username;
private String password;
public DbConfig(String driver, String url, String username,
String password){
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
this.url = url;
this.username = username;
this.password = password;
}
public String getUrl() {
return url;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
DbPoolConfig用來儲存物件池配置,通過繼承Apache Commons Pool提供的GenericObjectPoolConfig實現
提供了很多物件池相關的配置屬性以供使用
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class DbPoolConfig extends GenericObjectPoolConfig {
public DbPoolConfig(){
setMaxTotal(10);
setMaxIdle(5);
setMinIdle(2);
}
}
測試程式碼如下
import java.sql.Connection;
import java.sql.Statement;
public class Test {
public static void main(String[] args) throws Exception {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://192.168.137.128:3306/mydb";
String username = "root";
String password = "";
DbConfig dbConnectionConfig = new DbConfig(
driver, url, username, password);
DbConnectionFactory dbConnectionFactory = new DbConnectionFactory(dbConnectionConfig);
DbPoolConfig dbPoolConfig = new DbPoolConfig();
dbPoolConfig.setMaxTotal(10);
dbPoolConfig.setMaxIdle(5);
dbPoolConfig.setMinIdle(2);
dbPoolConfig.setMaxWaitMillis(200);
dbPoolConfig.setTestOnBorrow(false);
dbPoolConfig.setTestOnReturn(false);
DbPool dbPool = new DbPool(dbPoolConfig, dbConnectionFactory);
for(int i = 0 ; i < 20 ; i++){
Connection connection = dbPool.getConnection();
Statement statement = connection.createStatement();
statement.execute("insert into t_person(name, age) values ('a', 20)");
dbPool.returnConnection(connection);
}
}
}