写点什么

自定义 MySQL 连接池

作者:FunTester
  • 2022 年 6 月 27 日
  • 本文字数:3046 字

    阅读完需:约 10 分钟

最近在学习了通用池化框架commons-pool2实践之后,再 HTTP 性能测试中进行了实践,结果出乎意料,对于性能提升没啥卵用。经过我自己的本地测试,性能也是足够好的。


后来我仔细想了想,原来是我用错地方了。本来想自己写一个 Redis 的连接池的没想到,jedis的连接池本身就是commons-pool2开发的,让我有点意外,看来想的是一样的。commons-pool2用来做连接池是非常不错的。


我仔细找了找,发现还缺一个本地的 MySQL 连接池,而不是 springboot 那样需要启动一个服务才行。当然应该也是有的,不过我非常想自己写一个然后进行各类测试,所以也没有仔细找。

可池化对象

首先,我们需要一个可池化对象,这里我选用了com.funtester.db.mysql.FunMySql,这是一个我自己写的单链接的 MySQL 对象。我计划用这个作为基础可池化对象。


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操作的基础类 * <p>用于存储数据,多用于爬虫</p> */public class FunMySql extends SqlBase implements IMySqlBasic {
/** * {@link SqlConstant#FUN_SQL_URL}会替换IP到URL */ 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语句,并不关闭连接 * * @param sql */ @Override public void executeUpdateSql(String sql) { SqlBase.executeUpdateSql(connection, statement, sql); }
/** * 查询功能 * * @param sql * @return */ @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); }
}
复制代码

池化工厂

相对连接,创建com.funtester.db.mysql.FunMySql的时候,顺便一起初始化 MySQL 连接。然后再com.funtester.db.mysql.MysqlPool.FunTester#destroyObject的时候进行连接的回收。


    /**     * 池化工厂类     */    private class FunTester extends BasePooledObjectFactory<FunMySql> {
@Override FunMySql create() throws Exception { return new FunMySql(url, database, user, password) }
@Override PooledObject<FunMySql> wrap(FunMySql obj) { return new DefaultPooledObject<FunMySql>(obj) }
@Override void destroyObject(PooledObject<FunMySql> p) throws Exception { p.getObject().over() super.destroyObject(p) } }
复制代码

对象池

这里显得有些冗余,后面再使用过程中,我会继续优化。通过创建一个com.funtester.db.mysql.MysqlPool对象,获取一个com.funtester.db.mysql.FunMySql对象池。


/** * 自定义MySQL连接池对象 */class MysqlPool extends PoolConstant {
private static final Logger logger = LogManager.getLogger(MysqlPool.class);
/** * {@link com.funtester.config.SqlConstant#FUN_SQL_URL}会替换IP到URL*/ String url;
/** * 库 **/ String database;
/** * 用户 **/ String user;
/** * 密码 **/ String password;
private GenericObjectPool<FunMySql> pool
MysqlPool(String url, String database, String user, String password) { this.url = url this.database = database this.user = user this.password = password init() }
/** * 初始化连接池 * @return */ 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<FunMySql>(new FunTester(), poolConfig); }}
复制代码

API 封装

自从学习了 Go 语言的 gorm 框架和 Redis 框架,我发现其实不用把池化相关信息不用暴露出来,直接封装原始的 API,暴露给用户使用,这样用户就不用关心连接的回收问题了。



/** * 借出对象 * @return */ def borrow() { try { return pool.borrowObject() } catch (e) { logger.warn("获取${JSONObject.class} 失败", e) } finally { new JSONObject() } }
/** * 归还对象 * @param funMySql * @return */ def back(FunMySql funMySql) { pool.returnObject(funMySql) }
/** * 执行update SQL * @param sql * @return */ def execute(def sql) { def driver = borrow() try { driver.executeUpdateSql(sql) } catch (e) { logger.warn("执行:{}失败", sql) } finally { back(driver) } }
/** * 执行查询SQL * @param sql * @return */ def query(def sql) { def driver = borrow() try { return driver.executeQuerySql(sql) } catch (e) { logger.warn("执行:{}失败", sql) } finally { back(driver) } }
复制代码


BUG 挖掘机·性能征服者·头顶锅盖



阅读原文,跳转我的仓库地址

发布于: 刚刚阅读数: 4
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020.10.20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
自定义MySQL连接池_FunTester_InfoQ写作社区