jdbc学习笔记(2):使用连接池优化操作

文章目录

  • 1.连接池概述
  • 2.自定义连接池
    • 2.1改进
    • 2.2装饰者模式
    • 2.3一个简单的例子理解装饰者模式
    • 2.4装饰者模式实现自定义连接池`Connection.close()`方法归还连接
  • 3.常用连接池
    • 3.1dbcp
    • 3.2.c3p0(掌握)

使用jdbc时,每一次 操作都需要创建一个连接,然后销毁掉,可以通过连接池来进行资源的优化。

1.连接池概述

管理数据库的连接,提高系统性能,就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可.所有的连接池必须实现一个接口 javax.sql.DataSource接口。

  • 获取连接方法
    Connection getConnection()
    
  • 归还连接的方法
    connection.close()
    

2.自定义连接池

  • 新建一个类
/**
 * 20190802
 * 自定义一个连接池 重点在于理解连接池的思想
 * 就是先建立好若干数量的数据库连接 都放在一个“池子”里 有需要的时候 就申请从这个池子里获取
 * 试用完了 就把连接归还回来即可
 */
public class MyDataSource {
     
    //用来存放连接的连接池
    static LinkedList<Connection> pool = new LinkedList<>();
    static int linkNum = 3;//连接池数量上限
    //初始化
    static {
     
        for (int i=0; i<linkNum; i++){
     
            try {
     
                Connection conn = JDBCUtils.getConnection();
                pool.addLast(conn);
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
    }

    //从连接池中获取连接
    public static Connection getConnection(){
     
        //先要判断连接池中是否还有连接
        //若没有 先扩容
        if (pool.isEmpty()){
     
            for (int i=0; i<linkNum; i++){
     

                Connection conn = null;
                try {
     
                    conn = JDBCUtils.getConnection();
                    pool.addLast(conn);
                } catch (SQLException e) {
     
                    e.printStackTrace();
                }
            }
        }
        System.out.println("从连接池获取一个连接");
        return pool.removeFirst();
    }

    /**
     * 20190802
     * 归还连接
     * @param conn
     */
    public static void addBack(Connection conn){
     
        //将conn放在poll末尾即可
        pool.addLast(conn);
        System.out.println("归还一条连接");
    }
  • 测试
/**
 * 20190802
 * 测试自定义的连接池
 */
public class TestMyDS {
     
    public static void main(String[] args) {
     
        //创建连接池
        MyDataSource ds = new MyDataSource();
        //获取连接
        Connection conn = ds.getConnection();
        System.out.println(conn);
        //归还连接
        ds.addBack(conn);
    }
}

2.1改进

上述连接池归还连接的时候多了一个方法叫addBack(),但是标准的归还应该是close方法,但是在自定义工具类的时候,close方法实现的是销毁连接的功能,如何在不改变方法名和功能的时候,让同一个方法做更多的事情。

这里的问题本质上就是如何对一个方法进行增强,一般有三种方式:

  • 继承
  • 装饰者模式(静态代理)
  • 动态代理

下面详细讲解装饰者模式

2.2装饰者模式

  • 使用步骤
    • 1.装饰者和被装饰者实现同一个接口或者继承同一个类
    • 2.装饰者中要有被装饰者的引用
    • 3.对需要增强的方法进行增强
    • 4.对不需要增强的方法调用原方法即可

2.3一个简单的例子理解装饰者模式

定义了一个汽车接口,具有runstop的两种方法,一个具体的汽车Audi实现了这个接口,以5m/s的速度run,希望增强这个方法,让Audi的速度达到50m/s

  • 1.定义接口

    public interface Car {
           
        void run();
        void stop();
    }
    
  • 2.定义Audi类,实现接口

    public class Audi implements Car {
           
        
        @Override
        public void run() {
           
            System.out.println("5m/s");
        }
    
        @Override
        public void stop() {
           
            System.out.println("stopping");
    
        }
    }
    
  • 3.定义装饰者,实现Car接口,并增强方法

    public class CarWrap implements Car {
           
        private  Car car;
    
        /**
         * 构造函数 对所有继承了 Car接口的类都起作用
         * @param car
         */
        public CarWrap(Car car){
           
            this.car = car;
        }
    
        //增强方法
        @Override
        public void run(){
           
            System.out.println("speeding");
            System.out.println("50m/s");
        }
        @Override
        public void stop(){
           
            //不需要增强的方法 调用原方法即可
            car.stop();
        }
    }
    
  • 4.使用包装类

public class Test {
     
    public static void main(String[] args) {
     
        Audi audi = new Audi();
        audi.run();
        audi.stop();
        //测试装饰者模式
        // 对audi这个对象 增强
        CarWrap carWrap = new CarWrap(audi);
        //调用run方法可以发现 该方法执行的是被增强后的代码
        carWrap.run();
        carWrap.stop();
    }
}
  • 5.效果
    jdbc学习笔记(2):使用连接池优化操作_第1张图片

2.4装饰者模式实现自定义连接池Connection.close()方法归还连接

建立一个装饰者继承Connection类 然后对Connection.close()方法进行增强

  • 1.创建包装类继承Connection,增强close方法
public class ConnectionWrap implements Connection {
     

    private Connection conn;
    private LinkedList<Connection> pool;

    //构造方法 因为后面的close方法需要将一个连接归还给 pool,而pool是自定义的连接池实现的,所以需要在
    //装饰者类 初始化的时候 传进来
    public ConnectionWrap(Connection conn, LinkedList<Connection> pool){
     
        this.conn = conn;
        this.pool = pool;
    }

    /**
     * 20190802
     * close方法 需要增强的方法
     * @throws SQLException
     */
    @Override
    public void close() throws SQLException {
     
        System.out.println("前:" + pool.size());
        //当前连接归还到连接池
        pool.addLast(this);
        System.out.println("后:" + pool.size());
        System.out.println("归还一条连接到连接池");
    }


    /**
     * 不需要增强的方法 调用原始方法即可
     * @return
     * @throws SQLException
     */
    @Override
    public Statement createStatement() throws SQLException {
     
        return conn.createStatement();
    }

    //不需要增强的方法 调用原始方法即可
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
     
        return conn.prepareStatement(sql);
    }
}
  • 2.自定义连接池MyDataSourceWrap

关键在于 拿到连接后 需要经过装饰者装饰后才能返回

public class MyDataSourceWrap {
     
    //用来存放连接的连接池
    static LinkedList<Connection> pool = new LinkedList<>();
    static int linkNum = 3;//连接池数量上限
    //初始化
    //静态代码块 在类被加载的时候 就执行了
    static {
     
        for (int i=0; i<linkNum; i++){
     
            try {
     
                Connection conn = JDBCUtils.getConnection();
                pool.addLast(conn);
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
    }

    //从连接池中获取连接

    /**
     * 使用装饰者模式 实现close归还连接
     * @return
     */
    public static Connection getConnection(){
     
        //先要判断连接池中是否还有连接
        //若没有 先扩容
        if (pool.isEmpty()){
     
            for (int i=0; i<linkNum; i++){
     

                Connection conn = null;
                try {
     
                    conn = JDBCUtils.getConnection();
                    pool.addLast(conn);
                } catch (SQLException e) {
     
                    e.printStackTrace();
                }
            }
        }
        System.out.println("从连接池获取一个连接");
        Connection conn = pool.removeFirst();
        //这里获取到的连接 需要先被装饰后传出 才会具有close的效果
        ConnectionWrap myconn = new ConnectionWrap(conn, pool);
        return myconn;
    }

  • 3.测试

直接使用Connection.close即可归还连接到连接池

public class TestMyDSWrap {
     

    public static void main(String[] args) throws SQLException {
     
        //创建连接池
        MyDataSourceWrap ds = new MyDataSourceWrap();
        //获取连接
        Connection conn = ds.getConnection();
        System.out.println(conn);

        //归还连接
        conn.close();
    }
}
  • 4.结果
    jdbc学习笔记(2):使用连接池优化操作_第2张图片

3.常用连接池

3.1dbcp

apache组织开发的

使用步骤

  • 1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)
  • 2.使用api
    • a.硬编码方式
      • 建立连接池:BasicDataSource ds = new BasicDataSource();
      • 配置信息:
         ds.setDriverClassName("com.mysql.jdbc.Driver");
         ds.setUrl("jdbc:mysql://localhost:3306/day07");
         ds.setUsername("root");
         ds.setPassword("admin");
        
    • b.配置文件
      • 1.建立一个.properties文件,以key=value存放配置参数,注意里面的key和前文配置文件中的key不一样。
      • 2.创建连接池:DataSource ds = new BasicDataSourceFactory().createDataSource(prop);
         //存放配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("src/dbcp.properties"));
        //创建连接池
        DataSource ds = new BasicDataSourceFactory().createDataSource(prop);
        

3.2.c3p0(掌握)

hibernate和spring框架都使用了该连接池,有自动回收空闲连接功能。

  • 使用步骤
    • 1.导入jar包(c3p0-0.9.1.2.jar)

    • 2.使用api

      • a.硬编码(不推荐)
      //建立连接池
      ComboPooledDataSource ds = new ComboPooledDataSource();
      
      //设置基本参数
      ds.setDriverClass("com.mysql.jdbc.Driver");
      ds.setJdbcUrl("jdbc:mysql:///day07");
      ds.setUser("root");
      ds.setPassword("admin");
      
      • b.配置文件:c3p0.properties,注意配置文件的命名必须规范
      c3p0.driverClass=com.mysql.jdbc.Driver
      c3p0.jdbcUrl=jdbc:mysql:///day07
      c3p0.user=root
      c3p0.password=admin
      
       //建立连接池
      //可以看到 这里并没有任何关于配置文件的信息
      //说明配置文件按照规范的位置 和命名 c3p0可以自己查到
      ComboPooledDataSource ds = new ComboPooledDataSource();
      
      • c.配置文件:c3p0-config.xml的默认配置方式
      	<c3p0-config>
      	<!-- 默认配置,如果没有指定则使用这个配置 -->
      	<default-config>
      	<!-- 基本配置 -->
      	<property name="driverClass">com.mysql.jdbc.Driver</property>
      	<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/day07</property>
      	<property name="user">root</property>
      	<property name="password">admin</property>
      
      	<!--扩展配置-->
      	<property name="checkoutTimeout">30000</property>
      	<property name="idleConnectionTestPeriod">30</property>
      	<property name="initialPoolSize">10</property>
      	<property name="maxIdleTime">30</property>
      	<property name="maxPoolSize">100</property>
      	<property name="minPoolSize">10</property>
      	<property name="maxStatements">200</property>
         </default-config> 
      
      //建立连接池
      //可以看到 这里并没有任何关于配置文件的信息
      //说明配置文件按照规范的位置 和命名 c3p0可以自己查到
      ComboPooledDataSource ds = new ComboPooledDataSource();
      Connection conn=ds.getConnection();
      
    • 配置文件的c3p0-config.xml的命名配置方式

    通过指定命名的配置信息进行连接,若失败(命名输入错误)会再使用默认配置
    jdbc学习笔记(2):使用连接池优化操作_第3张图片
    jdbc学习笔记(2):使用连接池优化操作_第4张图片
    jdbc学习笔记(2):使用连接池优化操作_第5张图片

你可能感兴趣的:(JDBC,数据库,MyS)