网络知识 娱乐 自定义MySQL连接池

自定义MySQL连接池

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

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

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

可池化对象

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

package com.funtester.db.mysql;nnimport com.funtester.base.interfaces.IMySqlBasic;nimport com.funtester.config.SqlConstant;nnimport java.sql.Connection;nimport java.sql.ResultSet;nimport java.sql.Statement;nn/**n * mysql操作的基础类n * <p>用于存储数据,多用于爬虫</p>n */npublic class FunMySql extends SqlBase implements IMySqlBasic {nn /**n * {@link SqlConstant#FUN_SQL_URL}会替换IP到URLn */n String url;nn /**n * 库n */n String database;nn /**n * 用户n */n String user;nn /**n * 密码n */n String password;nn Connection connection;nn Statement statement;nn /**n * 私有构造方法n *n * @param url 连接地址,包括端口n * @param database 库n * @param user 用户名n * @param password 密码n */n public FunMySql(String url, String database, String user, String password) {n this.url = url;n this.database = database;n this.user = user;n this.password = password;n getConnection(database);n }nn /**n * 初始化连接n */n @Overriden public void getConnection() {n getConnection(EMPTY);n }nn /**n * 执行sql语句,非query语句,并不关闭连接n *n * @param sqln */n @Overriden public void executeUpdateSql(String sql) {n SqlBase.executeUpdateSql(connection, statement, sql);n }nn /**n * 查询功能n *n * @param sqln * @returnn */n @Overriden public ResultSet executeQuerySql(String sql) {n return SqlBase.executeQuerySql(connection, statement, sql);n }nn /**n * 关闭query连接n */n @Overriden public void over() {n SqlBase.close(connection, statement);n }nn @Overriden public void getConnection(String database) {n if (connection == null)n connection = SqlBase.getConnection(SqlConstant.FUN_SQL_URL.replace("ip", url).replace("database", database), user, password);n if (statement == null) statement = SqlBase.getStatement(connection);n }nn}nn

池化工厂

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

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

对象池

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

/**n * 自定义MySQL连接池对象n */nclass MysqlPool extends PoolConstant {nn private static final Logger logger = LogManager.getLogger(MysqlPool.class);nn /**n * {@link com.funtester.config.SqlConstant#FUN_SQL_URL}会替换IP到URL*/n String url;nn /**n * 库n **/n String database;nn /**n * 用户n **/n String user;nn /**n * 密码n **/n String password;nn private GenericObjectPool<FunMySql> poolnn MysqlPool(String url, String database, String user, String password) {n this.url = urln this.database = databasen this.user = usern this.password = passwordn init()n }nn /**n * 初始化连接池n * @returnn */n def init() {n GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();n poolConfig.setMaxTotal(MAX);n poolConfig.setMinIdle(MIN_IDLE);n poolConfig.setMaxIdle(MAX_IDLE);n poolConfig.setMaxWaitMillis(MAX_WAIT_TIME);n poolConfig.setMinEvictableIdleTimeMillis(MAX_IDLE_TIME);n pool = new GenericObjectPool<FunMySql>(new FunTester(), poolConfig);n }n}n

API封装

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

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

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