• 自定义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)
            }
        }
    
    

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

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

  • 相关阅读:
    List、Map、set的加载因子,默认初始容量和扩容增量
    spring事务处理
    根据url的属性名来取属性值赋值给js
    XStream JavaBean对象转换成XML!
    【转载:java】详解java中的注解(Annotation)
    Myeclipse修改jdk版本流程
    Bootstrap中文参考手册
    CSS3参考手册
    HTML 5 参考手册
    win7win8一键取得超级管理员权限
  • 原文地址:https://www.cnblogs.com/FunTester/p/16417594.html
Copyright © 2020-2023  润新知