最近在學習了通用池化框架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挖掘機·性能征服者·頭頂鍋蓋
- 性能測試專題
- Java、Groovy、Go、Python
- 單測&白盒
- FunTester社羣風采
- 測試理論雞湯
- 接口功能測試專題
- FunTester視頻專題
- 案例分享:方案、BUG、爬蟲
- UI自動化專題
- 測試工具專題
閱讀原文,跳轉我的倉庫地址