MySQL池化框架學習接池自定義

引言

最近在學習瞭通用池化框架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)
        }
    }

以上就是MySQL連接池自定義示例詳解的詳細內容,更多關於MySQL連接池自定義的資料請關註WalkonNet其它相關文章!

推薦閱讀: