• 数据连接池C3P0/DBCP/DRUID/自定义连接池


    1.C3P0连接池

    快速入门官网  https://www.mchange.com/projects/c3p0/#quickstart  

    <dependency>
    			<groupId>com.mchange</groupId>
    			<artifactId>c3p0</artifactId>
    			<version>0.9.5.2</version>
    </dependency>
    
    public class C3P0Pool {
    	public static void main(String[] args) throws PropertyVetoException, SQLException {
    		ComboPooledDataSource cpds = new ComboPooledDataSource();
    		cpds.setDriverClass("com.mysql.cj.jdbc.Driver"); 
    		cpds.setJdbcUrl("jdbc:mysql://localhost:3306/table?useUnicode="
    				+ "true&characterEncoding=utf8&characterSetResults=utf8&useSSL="
    				+ "false&verifyServerCertificate=false&serverTimezone=GMT%2B8 ");
    		cpds.setUser("root");
    		cpds.setPassword("cgz12345678");
    		//最大8
    		cpds.setMaxPoolSize(8);
    		//最小2个
    		cpds.setMinPoolSize(2);
    		//初始化2 介于MinPoolSize(2)与MaxPoolSize(8)之间
    		cpds.setInitialPoolSize(2);
    		//当连接数不足时每次补充2个
    		cpds.setAcquireIncrement(2);
    		//维护statement的总个数
    		cpds.setMaxStatements(70);
    		//每个连接可以使用的statement的个数
    		cpds.setMaxStatementsPerConnection(10);
    		//最大保持的空闲时间,否则被回收  与maxConnectionAge的区别是maxConnectionAge表示活着的总时间
    		cpds.setMaxIdleTime(60000);
    		Connection connection = cpds.getConnection();
    		System.out.println(connection);
    	}
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
        <named-config name="c3p0">
            <!-- 配置数据库链接地址 -->
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/user?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&serverTimezone=GMT%2B8</property>
            <!-- 配置数据库驱动 -->
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <!-- 当不足时,数据库连接池一次性向数据库要多少个连接对象 ,Default:3-->
            <property name="acquireIncrement">20</property>
            <!-- 初始化连接数,Default:3 -->
            <property name="initialPoolSize">10</property>
            <!-- 最小连接数 -->
            <property name="minPoolSize">5</property>
            <!--最大连接数。Default: 15 -->
            <property name="maxPoolSize">30</property>
            <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
    如果maxStatements为0,那么maxStatementsPerConnection无效,则缓存被关闭。Default:0 --> <property name="maxStatements">0</property> <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数如果设置的好能提高性能。Default: 0 --> <property name="maxStatementsPerConnection">0</property> <!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 通过多线程实现多个操作同时被执行。Default:3 --> <property name="numHelperThreads">3</property> <!--用户修改系统配置参数执行前最多等待300秒。Default: 300 --> <property name="propertyCycle">300</property> <!-- 获取连接超时设置 默认是一直等待,单位毫秒 --> <property name="checkoutTimeout">1000</property> <!--每多少秒检查所有连接池中的空闲连接。Default: 0 --> <property name="idleConnectionTestPeriod">3</property> <!--最大空闲时间,多少秒内未被使用则连接被丢弃。若为0则永不丢弃。单位秒,Default: 0 --> <property name="maxIdleTime">10</property> <!--配置连接的生存时间,单位秒,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限制。
    不为0则保持到minPoolSize --> <property name="maxIdleTimeExcessConnections">5</property> <!--两次连接中间隔时间,单位毫秒。Default: 1000 --> <property name="acquireRetryDelay">1000</property> <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。Default: null --> <property name="automaticTestTable">Test</property> <!-- 获取connnection时测试是否有效 --> <property name="testConnectionOnCheckin">true</property>
         <!-- 活着的总时间,单位秒 -->
         <property name="maxConnectionAge">12</property> </named-config> </c3p0-config>

    备注:可以按上述提供的官网书写相应的xml文件,或者是properties文件,但是名称分别必须为c3p0-config.xml和c3p0.properties,否则找不到,一个xml中可以配置多个c3p0但是<named-config name="c3p0"> 的name不同,假如在maven的 srcmain esources目录下,那么上述的获取方式为ComboPooledDataSource cpds = new ComboPooledDataSource("c3p0");

    2.DBCP

    api文档: http://commons.apache.org/proper/commons-dbcp/api-2.5.0/index.html  

    public class DBCPPoolTest {
    	public static void main(String[] args) throws SQLException {
    		BasicDataSource dataSource = new BasicDataSource();
    		dataSource.setUsername("root");
    		dataSource.setUrl("jdbc:mysql://localhost:3306/table?useUnicode="
    				+ "true&characterEncoding=utf8&characterSetResults=utf8&useSSL="
    				+ "false&verifyServerCertificate=false&serverTimezone=GMT%2B8 ");
    		dataSource.setPassword("12345678");
    		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    		dataSource.setInitialSize(1);// 初始化连接数
    		// 超过8个connection在规定的的等待时间之内得不到连接则会报错
    		dataSource.setMaxTotal(8);// 最大连接数
    		// 超过maxIdle值后,刚刚使用完的连接(刚刚空闲下来)会立即被销毁。
    		dataSource.setMaxIdle(3);// 最大的空闲数,一般设置为MaxTotal的一半
    		dataSource.setMinIdle(2);// 默认是0 ,一般设置比较小为好,尽量减少连接数的空闲占用,当不足以保证时,就维持现状,当有还给连接池的对象时,又添加来保持自己
    		dataSource.setMaxWaitMillis(60000);// 连接池分配连接的最大时间,超过会报出异常
    		// 池中的连接空闲时间,超过被回收默认值就是30分钟
    		dataSource.setMinEvictableIdleTimeMillis(3000000);
    		Connection con = dataSource.getConnection();
    		System.out.println(con);
    		con.close();// 并非真正的关闭,而是将其归还到线程池
    		dataSource.close();
    	}
    }
    
    #类似c3p0的driverClass
    driverClassName=com.mysql.jdbc.Driver 
    #传递给JDBC驱动的用于建立连接的URL
    #当设置characterEncoding时useUnicode=true必须设置,characterEncoding指按指定编码解码成字节码,autoReconnect=true当数据库连接中断时是否自动重新连接,autoReconnect=true但是这个连接两次访问数据库的时间超出了服务器端wait_timeout的时间限制,还是会CommunicationsException,dontTrackOpenResources要求驱动自动跟踪和关闭资源,如果不能明确的调用作用在语句或者结果集上的close时,会造成内存溢出,设置为true可以提高某些程序的内存效率 默认false
    url=jdbc:mysql://localhost:3306/testjdbc?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&dontTrackOpenResources=true
    #传递给JDBC驱动的用于建立连接的用户名
    username=root
    #传递给JDBC驱动的用于建立连接的密码
    password=cgz12345678
    #初始化连接:初始化连接数量,1.2版本后支持  默认值0  jdbc-pool默认值10
    initialSize=5
    #最大活动连接:如果设置为非正数则表示不限制 默认值8 jdbc-pool默认值100
    maxActive=8
    #最大空闲连接:超过的空闲连接将被释放,如果设置为负数表示不限制 默认值8 jdbc-pool默认值
    maxIdle=20
    #最小空闲连接,低于这个数量将创建新的连接,如果设置为0则不创建 默认值0 jdbc-pool默认值10
    minIdle=5
    #最大等待时间: (以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待 默认值:无限  jdbc-pool默认值30000ms
    maxWait=28000
    #连接池创建的连接的默认的auto-commit状态,默认值true
    defaultAutoCommit=true
    #当设置了set-onlyread,则默认值为only-read模式,当没有设置的时候不会被调用,(不支持只读模式) (某些驱动不支持只读模式,比如:Informix)
    defaultReadOnly 
    #连接池创建的连接的默认的TransactionIsolation状态. Jdbc事物隔离级别中的一个
    defaultTransactionIsolation= READ_COMMITTED
    #连接池创建的连接的默认的catalog
    defaultCatalog
    #是否自动回收超时连接,默认值false,这个是由前提条件的,当空闲连接数小于一定数量的时候才会被触发,类似垃圾回收,回收的前提是响应时间超过removeAbandonedTimeout时间
    removeAbandoned=true
    #超过相应的时间没响应就回收, 单位秒 默认300
    removeAbandonedTimeout=300
    #是否在自动回收超时连接的时候打印连接的超时错误,默认值false jdbc-pool默认值false
    logAbandoned=true
    #SQL查询验证语句至少返回一条语句
     validationQuery=select 1
    #指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
    #如果设置为true后如果要生效那么validationQuery参数必须设置为非空字符串 默认值:true,对连接前进行相应的检验,检验失败,则删除连接,尝试下一条连接
    testOnBorrow=true
    #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串   默认值: false jdbc-pool默认值false,指明是否在归还到池中前进行检验
    testOnReturn=true
    #指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败(检测是以timeBetweenEvictionRunsMilli为依据,如果超过这个时间则进行validationQuery检测连接是否有效),则连接将被从池中去除.设置为true后如果要生效,validationQuery参数必须设置为非空字符串  默认值: false
    testWhileIdle=true
    #空闲连接回收器线程运行时间间隔,以毫秒为单位. 如果设置为非正数,则不运行空闲连接回收器线程  默认值: -1  jdbc-pool的默认值为5000ms
    timeBetweenEvictionRunsMilli=-1
    #每次空闲连接回收器线程(如果有)运行时检查的连接数量 默认值:1000 * 60 * 30
    numTestsPerEvictionRun
    #保存空闲而不被空闲回收器回收的间隔时间
    minEvictableIdleTimeMillis
    #开启池的prepared statement 池功能  默认值false
    poolPreparedStatements
    #statement池能够同时分配的打开的statements的最大数量, 如果设置为0表示不限制 默认值:不限制
    maxOpenPreparedStatements=0
    #这里可以开启PreparedStatements池. 当开启时, 将为每个连接创建一个statement池,并且被下面方法创建的PreparedStatements将被缓存起来:
    #PoolGuard是否容许获取底层连接 默认值false
    #如果容许则可以使用下面的方式来获取底层连接:
     #   Connection conn = ds.getConnection();
     #   Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate();
     #  ...
     #   conn.close();
    #注意: 不要关闭底层连接, 只能关闭前面的那个.
    accessToUnderlyingConnectionAllowed
    4.2创建方法
    方式1
    final BasicDataSource dataSource = new BasicDataSource();
    	dataSource.setUsername("root");
    	dataSource.setPassword("cgz12345678");
    	dataSource.setUrl("jdbc:mysql://localhost:3306/testjdbc");
    	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    	dataSource.setInitialSize(5);
    	dataSource.setMaxActive(5);
    	dataSource.setMinIdle(2);
    	dataSource.setMaxWait(1000*5);
    方式2
        Properties properties = new Properties();
    	InputStream stream = jdbctestc3p0_dbcp.class.getClassLoader().getResourceAsStream("2.properties");
    	try {
    		properties.load(stream);
    		DataSource dataSource = 
    				BasicDataSourceFactory.createDataSource(properties);
    		BasicDataSource source =(BasicDataSource)dataSource;
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    Properties文件
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/testjdbc
    username=root
    password=cgz12345678
    
    DBCP 是单线程的,为了保证线程安全会锁整个连接池
    DBCP 性能不佳
    DBCP 太复杂,超过60个类,发展滞后
    还有其它的高性能连接池,如C3P0,还有阿里系的druid等
    

    3)DRUID

    API官方文档https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE    

    #驱动类名。
    driverClassName=com.mysql.jdbc.Driver
    #连接数据库的url
    url=jdbc:mysql://127.0.0.1:3306/day25
    #数据库的用户名
    username=root
    #数据库的密码
    password=12345678
    #初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
    initialSize=5
    #最大连接池数量
    maxActive=10
    #获取连接时最大等待时间
    maxWait=3000
    #已经不再使用,配置了也没效果
    maxIdle=6
    #最小连接池数量
    minIdle=3
    
    // 加载配置文件中的配置参数
    InputStream is = Demo03.class.getResourceAsStream("/druid.properties");
    Properties pp = new Properties();
    pp.load(is);
    // 创建连接池,使用配置文件中的参数
    DataSource ds = DruidDataSourceFactory.createDataSource(pp);
    

     备注:连接池超标报异常

    4)自定义线程池

    package cn.test.javamail.massage;
    
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import sun.applet.Main;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PrintWriter;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Properties;
    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.logging.Logger;
    
    public  class MyDataSourcePool  implements DataSource {
        private int initCount ;
        private int maxCount ;
        private int curCount  ;
    
        private List<Connection>  list=  new LinkedList();
    
        public MyDataSourcePool(int initCount, int maxCount) throws SQLException, IOException, ClassNotFoundException {
            this.initCount = initCount;
            this.maxCount = maxCount;
            for (int i = 0; i < initCount; i++) {
                Connection connect = getConnect();
                list.add(connect);
                curCount++;
            }
        }
    
        @Override
        public Connection getConnection() throws SQLException {
            Connection connection=null;
            if(list.size()>0){
                connection = list.get(0);
                list.remove(0);
            }else  if(curCount<maxCount){
                try {
                    Connection connect = getConnect();//不足的时候每次创建一个
                    list.add(connect);
                    curCount++;
                    connection = list.get(0);
                    list.remove(0);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else{
                new RuntimeException("已经满了");
            }
            return connection;
        }
    
        public  void close(Connection connect){//c3p0的close重写内部的方法
            list.add(connect);
        }
        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            return null;
        }
    
        @Override
        public <T> T unwrap(Class<T> iface) throws SQLException {
            return null;
        }
    
        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
            return false;
        }
    
        @Override
        public PrintWriter getLogWriter() throws SQLException {
            return null;
        }
    
        @Override
        public void setLogWriter(PrintWriter out) throws SQLException {
    
        }
    
        @Override
        public void setLoginTimeout(int seconds) throws SQLException {
    
        }
    
        @Override
        public int getLoginTimeout() throws SQLException {
            return 0;
        }
    
        @Override
        public Logger getParentLogger() throws SQLFeatureNotSupportedException {
            return null;
        }
    
        public  Connection  getConnect() throws IOException, ClassNotFoundException, SQLException {
            Properties ps = new Properties();
            InputStream is = this.getClass().getClassLoader().getResourceAsStream("config.properties");
            ps.load(is);
            Class.forName(ps.getProperty("driverClass"));
            Connection connection = DriverManager.getConnection(ps.getProperty("url"), ps);
            return connection;
        }
    
    }
    
  • 相关阅读:
    快速排序理论---不含源码
    归并排序理论---不含源码
    希尔排序(shell)理论---不含源码
    Visual C++中error spawning cl.exe解决办法
    数据库的基础知识点---1
    冒泡排序的基础知识部分(不含源码)
    在虚拟机的Linux系统下安装wineqq
    数据变量的别名
    void*和void类型
    变量的作用域和连接性
  • 原文地址:https://www.cnblogs.com/gg128/p/9788105.html
Copyright © 2020-2023  润新知