连接池

一、为什么会产生连接池?

我们现在考虑:

程序中连接为什么要来管理?因为连接资源宝贵,所以我们要来对连接资源进行管理

如何高效的来进行管理?频繁的连接,打开、关闭,这会严重影响程序的运行效率!所以我们引入连接池的概念。

二、何为连接池?

普通的连接:

  1. 操作数据库,创建连接。
  2. 操作结束,关闭!

使用连接池管理:

  1. 预先创建一组连接,有的时候每次取出一个。
  2. 用完后,放回。

连接池就好比图书馆,我们想要看书去借阅,看完之后我们要归还。就是借与还的关系。

三、学习连接池

 3.1、自定义连接池

/*
     *  * 自定义连接池, 管理连接
     * 代码实现:
    1.  MyPool.java  连接池类,   
    2.  指定全局参数:  初始化数目、最大连接数、当前连接、   连接池集合
    3.  构造函数:循环创建3个连接
    4.  写一个创建连接的方法
    5.  获取连接
    ------>  判断: 池中有连接, 直接拿
     ------>                池中没有连接,

    ------>                 判断,是否达到最大连接数; 达到,抛出异常;没有达到最大连接数,

    创建新的连接
    6. 释放连接
     ------->  连接放回集合中(..)
     */
    private int init_count=3;  //初始化连接数目
    private int max_count=6;   //最大连接数目
    private int current_count=0; //记录当前使用连接数目
    //连接池,存放所有的初始化连接
    private LinkedList<Connection> pool=new LinkedList<Connection>();
    
    //1.构造函数,初始化连接放入连接池
    public MyPool(){
        for(int i=0;i<init_count;i++){
            //记录当前的数目
            current_count++;
            //创建原始的连接对象,加入连接池
            pool.addLast(createConnection());
        }
    }
    
    //2. 创建一个新的连接的方法
    //使用代理模式,来监测 close方法,当关闭时候,自动加入连接池
    private Connection createConnection(){
        
        try {
            Class.forName("com.mysql.jdbc.Driver");
            final Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_demo", "root", "root");
            Connection proxy=(Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), new Class[]{Connection.class}, 
                    new InvocationHandler() {
                        
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args)
                                throws Throwable {
                            // TODO Auto-generated method stub
                            Object result=null;
                            String name=method.getName();
                            if("close".equals(name)){
                                if(pool.size()<init_count){
                                System.out.println("begin:当前执行close方法开始!");
                                // 连接放入连接池 (判断..)
                                pool.addLast(conn);
                                System.out.println("end: 当前连接已经放入连接池了!");
                                }else{
                                    current_count--;
                                    conn.close();
                                }
                            }else{
                                method.invoke(conn, args);
                            }
                            return result;        
                        }
                        
                    }
                    );
            return proxy;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    
    
    //获得连接
    public Connection getConnection(){
        if(pool.size()>0){ //连接池有,直接获取
            return pool.removeFirst();
        }
        if(current_count<max_count){ //连接池没有,小于最大连接,自己创建连接
            current_count++;
            return createConnection();
        }
        throw  new RuntimeException();//没有连接使用,抛出异常
        
    }
    
    //释放连接
    public void realeaseConnection(Connection conn){
        if(pool.size()<init_count){
            pool.addLast(conn);
        }else{
            current_count--;
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    

 为什么使用LinkedList集合?

因为LinkedList集合含有.removeFirst()方法,这样我们可以删除第一个元素,并且返回第一个元素

3.2开源的连接池技术

概述:

Sun公司约定: 如果是连接池技术,需要实现一个接口! javax.sql.DataSource;

3.2.1、DBCP连接池

核心类:BasicDataSource

// 1. 硬编码方式实现连接池
        @Test
        public void testDbcp() throws Exception {
            BasicDataSource bds=new BasicDataSource(); //创建核心类
            bds.setDriverClassName("com.mysql.jdbc.Driver"); //数据库驱动
            bds.setUrl("jdbc:mysql://localhost:3306/jdbc_demo"); //数据库连接字符
            bds.setUsername("root"); //数据库用户名
            bds.setPassword("root");//数据库密码
            bds.setInitialSize(3); //初始化连接
            bds.setMaxActive(6);//最大连接数目
            bds.setMaxIdle(3000);//最大休闲时间
            String sql="select * from admin where id=5";
            //获取连接
            Connection conn=bds.getConnection();
            PreparedStatement pstmt=conn.prepareStatement(sql);
            System.out.println(pstmt.execute());
            conn.close();
        }
        
        
        // 2. 【推荐】配置方式实现连接池  ,  便于维护
        @Test
        public void testDBCP() throws Exception {
             // 获取文件流
            InputStream inputStream=App_DBCP.class.getResourceAsStream("/db.properties");
            // 加载prop配置文件
            Properties prop=new Properties();
            prop.load(inputStream);
            
            // 根据prop配置,直接创建数据源对象
            DataSource ds=BasicDataSourceFactory.createDataSource(prop);
            String sql="select * from admin where id=5";
            //获取连接
            Connection conn=ds.getConnection();
            PreparedStatement pstmt=conn.prepareStatement(sql);
            System.out.println(pstmt.execute());
            conn.close();
        }

配置文件为db.properties,配置文件中的keyBaseDataSouce中的属性一样:

url=jdbc:mysql://localhost:3306/jdbc_demo
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=3
maxActive=6
maxIdle=3000

3.2.1、DBCP连接池

C3P0连接池:

最常用的连接池技术!Spring框架,默认支持C3P0连接池技术!

C3P0连接池,核心类:

CombopooledDataSource ds;

package cn.lyjs.c3p0;

import static org.junit.Assert.*;

import java.sql.Connection;

import org.junit.Test;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0 {
    
    //1. 硬编码方式,使用C3P0连接池管理连接
    @Test
    public void testCode() throws Exception {
        // 创建连接池核心工具类
        ComboPooledDataSource dataSource=new ComboPooledDataSource();
        // 设置连接参数:url、驱动、用户密码、初始连接数、最大连接数
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc_demo");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setInitialPoolSize(3);
        dataSource.setMaxPoolSize(6);
        dataSource.setMaxIdleTime(3000);
        String sql="delete from admin where id=6";
        Connection conn=dataSource.getConnection();
        conn.prepareStatement(sql).executeUpdate();
        conn.close();
    }
    
    //2. XML配置方式,使用C3P0连接池管理连接
    @Test
    public void testXml() throws Exception {
                // 创建c3p0连接池核心工具类
                // 自动加载src下c3p0的配置文件【c3p0-config.xml】
        ComboPooledDataSource dataSource=new ComboPooledDataSource();
        String sql="delete from admin where id=7";
        Connection conn=dataSource.getConnection();
        conn.prepareStatement(sql).executeUpdate();
        conn.close();
    }
}
c3p0-config.xml,配置文件
<c3p0-config>
    <default-config>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc_demo</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">6</property>
        <property name="maxIdleTime">1000</property>
    </default-config>


    <named-config name="oracle_config">
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc_demo</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">6</property>
        <property name="maxIdleTime">1000</property>
    </named-config>


</c3p0-config>
原文地址:https://www.cnblogs.com/lyjs/p/5041656.html