Implementing a Custom MySQL Connection Pool with Apache Commons Pool2 in Java
The article explains how to build a reusable MySQL connection pool in Java using Apache Commons Pool2, detailing the creation of a poolable object, a factory class, the pool configuration, and a simple API wrapper for borrowing and returning connections while providing full source code examples.
After experimenting with the Apache commons-pool2 library and finding little performance improvement in HTTP tests, the author realized the library is ideal for creating custom connection pools such as Redis's Jedis pool.
The author defines a poolable object com.funtester.db.mysql.FunMySql , a lightweight wrapper around a single MySQL connection, and provides its full implementation.
package com.funtester.db.mysql;
import com.funtester.base.interfaces.IMySqlBasic;
import com.funtester.config.SqlConstant;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* mysql操作的基础类
*
用于存储数据,多用于爬虫
*/
public class FunMySql extends SqlBase implements IMySqlBasic {
String url;
String database;
String user;
String password;
Connection connection;
Statement statement;
/**
* 私有构造方法
* @param url 连接地址,包括端口
* @param database 库
* @param user 用户名
* @param password 密码
*/
public FunMySql(String url, String database, String user, String password) {
this.url = url;
this.database = database;
this.user = user;
this.password = password;
getConnection(database);
}
/** 初始化连接 */
@Override
public void getConnection() {
getConnection(EMPTY);
}
/** 执行sql语句,非query语句,并不关闭连接 */
@Override
public void executeUpdateSql(String sql) {
SqlBase.executeUpdateSql(connection, statement, sql);
}
/** 查询功能 */
@Override
public ResultSet executeQuerySql(String sql) {
return SqlBase.executeQuerySql(connection, statement, sql);
}
/** 关闭query连接 */
@Override
public void over() {
SqlBase.close(connection, statement);
}
@Override
public void getConnection(String database) {
if (connection == null)
connection = SqlBase.getConnection(SqlConstant.FUN_SQL_URL.replace("ip", url).replace("database", database), user, password);
if (statement == null) statement = SqlBase.getStatement(connection);
}
}The pool factory class creates and wraps FunMySql instances, handling object destruction by closing the underlying connection.
private class FunTester extends BasePooledObjectFactory
{
@Override
FunMySql create() throws Exception {
return new FunMySql(url, database, user, password);
}
@Override
PooledObject
wrap(FunMySql obj) {
return new DefaultPooledObject
(obj);
}
@Override
void destroyObject(PooledObject
p) throws Exception {
p.getObject().over();
super.destroyObject(p);
}
}The custom pool com.funtester.db.mysql.MysqlPool configures a GenericObjectPool with max total, idle limits, and wait times, then provides methods to borrow and return FunMySql objects.
class MysqlPool extends PoolConstant {
private static final Logger logger = LogManager.getLogger(MysqlPool.class);
String url;
String database;
String user;
String password;
private GenericObjectPool
pool;
MysqlPool(String url, String database, String user, String password) {
this.url = url;
this.database = database;
this.user = user;
this.password = password;
init();
}
def init() {
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(MAX);
poolConfig.setMinIdle(MIN_IDLE);
poolConfig.setMaxIdle(MAX_IDLE);
poolConfig.setMaxWaitMillis(MAX_WAIT_TIME);
poolConfig.setMinEvictableIdleTimeMillis(MAX_IDLE_TIME);
pool = new GenericObjectPool
(new FunTester(), poolConfig);
}
}A thin API wrapper hides the pooling details from callers. The borrow() method obtains a FunMySql from the pool, while back() returns it. Convenience methods execute() and query() run update and query statements respectively, ensuring the connection is always returned.
def borrow() {
try {
return pool.borrowObject()
} catch (e) {
logger.warn("获取${JSONObject.class} 失败", e)
} finally {
new JSONObject()
}
}
def back(FunMySql funMySql) {
pool.returnObject(funMySql)
}
def execute(def sql) {
def driver = borrow()
try {
driver.executeUpdateSql(sql)
} catch (e) {
logger.warn("执行:{}失败", sql)
} finally {
back(driver)
}
}
def query(def sql) {
def driver = borrow()
try {
return driver.executeQuerySql(sql)
} catch (e) {
logger.warn("执行:{}失败", sql)
} finally {
back(driver)
}
}Images illustrate the testing process, and a list of related articles and community resources is provided at the end.
FunTester
10k followers, 1k articles | completely useless
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.