zoukankan      html  css  js  c++  java
  • 浅析数据库连接池(二)

    上一篇博客,主要是简单的介绍了普通数据库连接的过程以及耗费的资源,并且简单的谈了下连接池,这篇我们主要来看看数据库连接池的使用以及它最优的配置。


    总文件夹:
    -1.数据库连接过程是如何的?
    -2.连接所占用的资源有哪些?
    -3.连接池简单介绍
    -4.连接池的使用
    -5.最优连接池配置选择

    今天主要看看4和5。


    4.连接池的使用

    这里我使用的是c3p0数据库连接池
    简单的介绍一下c3p0:C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定。支持JDBC3规范和JDBC2的标准扩展。眼下使用它的开源项目有Hibernate,Spring等。

    连接池的种类也有非常多,并且每种也有不同的适用场景。所以选择适合自己的连接池也是一方面~


    先放不使用连接池和使用连接池的数据对照。
    循环连接10次,图片为測试的第10组数据。

    不使用连接池
    这里写图片描写叙述


    使用连接池
    红色为连接池部分配置信息
    这里写图片描写叙述


    从图片我们能够明显的看出,连接池的速度要快于普通连接非常多,这里非常多不是指的二者差多少毫秒,而是倍数的区别。


    java连接池代码:

    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import java.awt.color.ProfileDataException;
    import java.beans.PropertyVetoException;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ResourceBundle;
    
    /**
     * Created by wwh on 15-6-10.
     */
    public class DBPollClass {
        private static DBPollClass dbPoll;
        private ComboPooledDataSource dbSource;
    
        //静态代码块,一開始我们就运行构造函数载入配置信息
        static {
            dbPoll = new DBPollClass();
        }
    
        public DBPollClass(){
            //设置配置信息
            try{
                dbSource = new ComboPooledDataSource();
                dbSource.setUser("root");
                dbSource.setPassword("123456789");
                dbSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/XL_db?user=root&password=123456789&useUnicode=true");
                dbSource.setDriverClass("com.mysql.jdbc.Driver");
                dbSource.setInitialPoolSize(1);
                dbSource.setMinPoolSize(2);
                dbSource.setMaxPoolSize(10);
                dbSource.setMaxStatements(50);
                dbSource.setMaxIdleTime(60);
            }catch (PropertyVetoException e){
                throw new RuntimeException(e);
            }
        }
    
        //获得连接
        public final static DBPollClass getInstance(){
            return dbPoll;
        }
    
        public final Connection getConnection(){
            try{
                return dbSource.getConnection();
            }catch (SQLException e){
                throw new RuntimeException("无法获取连接", e);
            }
        }
    
        public static void main(String[] args) throws SQLException {
            for(int i = 0; i < 10; i++) {
                long begintime = System.currentTimeMillis();
                Connection con = null;
                try {
                    //取得空暇连接
                    con = dbPoll.getInstance().getConnection();
                    //运行sql语句并返回查询结果
                    //ResultSet rs = con.createStatement().executeQuery("SELECT * from UserInfo");
                    //使用PreparedStatement而不使用Statement
                    PreparedStatement pst = con.prepareStatement("SELECT * from UserInfo");
                    ResultSet rs = pst.executeQuery();
                    //输出查询结果
                    while (rs.next()) {
                        System.out.println(rs.getObject(1) + " " + rs.getObject(2) + " " + rs.getObject(3) + " " + rs.getObject(4));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (con != null) {
                        //归还空暇连接
                        con.close();
                    }
                }
                long endtime = System.currentTimeMillis();
                System.out.println((i+1) + " time is:" + (endtime-begintime));
            }
        }
    }

    从代码我们能够和清晰的看出连接池的使用是非常easy的。代码中我将连接池的配置等信息写到了构造函数中,事实上现实中使用我们一般写在c3p0-config.xml。数据库连接池的配置文件里,然后放到src文件夹下就可以。
    连接池的使用步骤和普通的JDBC连接数据库基本一样。參数也相似
    只不过部分含义不同,连接池的connection,并非创建连接,而是从数据库连接池中间找出一个空暇的连接。con.close()也不是断开连接,而是归还给连接池。
    还有注意我们不只要归还connection资源。还要归还Preparedstatement和ResultSet的资源
    我们也须要养成良好的习惯使用Preparedstatement而不是statement。由于Preparedstatement里面包括了部分已经编译好的sql语句,能够提高运行速度。


    5.最优连接池配置选择

    使用和使用好两个词是截然不同的,我们的目的不不过使用线程池或者数据库连接池,而是通过使用它们来发挥server最大威力以及效率达到最优。


    这就要我们依据自己server配置信息来选择參数了~。
    先看看代码中我们设定了哪些參数。

    设置初始化连接池大小
    dbSource.setInitialPoolSize(1);

    设置连接池内最小连接数
    dbSource.setMinPoolSize(2);

    设置连接池内最大连接数
    dbSource.setMaxPoolSize(10);

    用来控制Preparedstatement的数量
    dbSource.setMaxStatements(50);

    最大空暇时间,60秒内未使用连接则被丢取。设置为0则永不丢弃
    dbSource.setMaxIdleTime(60);
    以上为经常使用和关键的參数。


    关于最关键的參数设定
    1.最小连接数
    连接池一直保持的数据库连接。

    最小连接数的大小我们要依据实际的使用情况不断的測试来决定,假设设定大了就会有很多空暇的连接,浪费了资源。

    2.最大连接数
    连接池的连接上限,一般当连接值大于最小连接数时,连接池就会创建新的connection来接受连接,我们设定的超时时间就是针对新创建的连接的,当使用完最小连接数外的连接时,它们不会被马上释放,而是停留MaxIdleTime时间。假设在MaxIdleTime时间没有再次被连接,则释放。假设超过最大连接数,那么新到的连接会被增加到等待队列中。

    3.最大空暇时间MaxIdleTime,这个要依据实际情况来调整设定了。

    假设最小连接数和最大连接数相差非常大,那么最先到的连接最获利,连接速度非常快,后到的会略微慢点,由于要创建连接。

    我们一般设定池的大小时,比方线程池。首先要确定是CPU密集型还是IO密集型。假设是CPU密集型。那么我们假设线程池设定应该和CPU核数差点儿一致,由于此时大量的计算,假设线程数量设定过大。那么线程切换消耗的时间就是主要花费,假设是IO密集型。那么线程数量要大于CPU数量,由于线程可能堵塞在IO处。所以堵塞时要切换其它线程继续运行,效率会高。

    那么訪问数据库是IO密集型的。由于内部也是创建单独的线程来连接,所以相似线程池。线程池IO密集型线程数计算公式为:
    线程数 = CPU核数 / (1-堵塞系数),堵塞系数也应该依据我们详细情况来分析。
    一般线程数为核心数的几倍。


    我就简单的介绍到这里,上面所说也是依据自己现有的知识和查询的资料来描写叙述的。并不一定所有正确,希望大家带着审视的眼光来看,假设哪部分错了。还望指出。谢谢~

  • 相关阅读:
    NodeJS Stream 五:双工流
    NodeJS Stream 四:Writable
    NodeJS Stream 三:readable
    NodeJS Stream 二:什么是 Stream
    NodeJS stream 一:Buffer
    JavaScript 精粹
    详解k8s中的liveness和readiness的原理和区别_转
    通过 GoLang 全面了解 HTTPS_转自知乎-腾讯技术
    golang之vim和vscode开发环境
    go命令工具补遗
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5378207.html
Copyright © 2011-2022 走看看