首頁 > 軟體

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

2022-07-21 14:00:30

引言

最近在學習了通用池化框架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連線池自定義的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com