什么是数据池?-简单的例子

什么是数据池?

  • 前言:
  • 关于数据池的概念
  • 简单数据池的实现
          • 不使用数据池的情况
          • 使用数据池的情况
  • 简单的实验一下

前言:

本文参考:https://segmentfault.com/a/1190000013308078

关于数据池的概念

连接池用于创建和管理数据库连接的缓冲池技术,缓冲池中的连接可以被任何需要他们的线程使用。当一个线程需要用JDBC对一个数据库操作时,将从池中请求一个连接。当这个连接使用完毕后,将返回到连接池中,等待为其他的线程服务。

详细可看:何为数据库连接池?其工作原理是什么?

简单数据池的实现

话不多说直接贴代码

不使用数据池的情况

注:在这个类中封装了数据库基本的连接操作和一个最简单的insert方法以便后面进行两种情况下效率对比的实验。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author void
 * @date 2020/3/26/14:08
 * 不使用数据池的数据库操作方式
 */
public class JDBCUtil {

    private static String URL = null;
    private static String DRIVERS = null;
    private static String USERNAME = null;
    private static String PASSWORD = null;

    static {

        try{
            URL = "jdbc:mysql://localhost:3306/blog";
            DRIVERS = "com.mysql.jdbc.Driver";
            USERNAME = "root";
            PASSWORD = "Peng1104.";

            Class.forName(DRIVERS);

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    // 通过DriverManger获取连接对象
    public static Connection getConnection() throws SQLException{
        return DriverManager.getConnection(URL,USERNAME,PASSWORD);
    }

    public static void insert(String sql, Connection conn, PreparedStatement pre){
        try {
            pre = conn.prepareStatement(sql);
            pre.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void clear(Connection conn, PreparedStatement pre){
        try {

            if(pre != null){
                pre.close();
            }

            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}


使用数据池的情况

注:

  1. 使用双向链表模拟数据池,当获取连接时调用removeFirst()方法取出链表中的一个连接对象。
  2. 当操作完毕时,不能直接调用Connection对象的close()方法释放资源,而是应该将原本取出的Connection对象放回数据池(链表)中。于是,使用匿名内部类的方式动态代理Connection对象的close()方法。而该类的getConnection返回的则是代理过的Connection对象。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedList;

/**
 * @author void
 * @date 2020/3/26/11:11
 */
public class JDBCPoolUtil {

    private static LinkedList<Connection> list = new LinkedList<>();

    static {

        try{
            final String URL = "jdbc:mysql://localhost:3306/blog";
            final String DRIVERS = "com.mysql.jdbc.Driver";
            final String USERNAME = "root";
            final String PASSWORD = "Peng1104.";

            Class.forName(DRIVERS);

            for(int i = 0; i < 10; i++){
                Connection connection = DriverManager.getConnection(URL,USERNAME,PASSWORD);
                list.add(connection);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    // 从数据池获取连接的方法
    public static Connection getConnection() throws SQLException{

        if(list.size() > 0){
            final Connection connection = list.removeFirst();

            System.out.println("池中还有 "+list.size()+" 空闲连接可用");
            // 动态代理JDBCPoolUtil中的Close方法
            return (Connection) Proxy.newProxyInstance(JDBCPoolUtil.class.getClassLoader(), connection.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 只对close方法进行代理
                    if(method.getName().equals("close")){
                        // 将连接归还到连接池中
                        list.add(connection);

                        System.out.println("此时,池中还有 "+ list.size() +" 空闲连接可用");
                    }else{
                        return method.invoke(connection, args);
                    }
                    return null;
                }
            });
        }
        return null;
    }

    public static void insert(PreparedStatement pre){
        try {
            pre.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void clear(Connection conn, PreparedStatement pre){
        try {

            if(pre != null){
                pre.close();
            }

            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

简单的实验一下

进行对照实验,比较是否使用数据池对数据库操作效率的影响,
注:比较的是每次操作新建连接和事先建好连接每次从数据池里取的区别。所以每次操作都要释放连接

import java.sql.*;

/**
 * @author void
 * @date 2020/3/25/1:31
 */
public class Main {

    public static void main(String[] args) {

        String sql = "insert into user values(null,'hello','123','[email protected]','456')";

        Long startTime = System.currentTimeMillis();
        for(int i = 0; i < 10; i++){
            try {
                Connection conn = JDBCUtil.getConnection();
                PreparedStatement pre = conn.prepareStatement(sql);
                JDBCUtil.insert(sql,conn,pre);
                // 释放资源
                JDBCUtil.clear(conn,pre);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        Long endTime = System.currentTimeMillis();
        System.out.println("不使用连接池耗时:"+ (endTime - startTime) +"毫秒");



        Long startTime1 = System.currentTimeMillis();
        for (int i = 0; i < 10; i++){
            try {
                Connection conn = JDBCPoolUtil.getConnection();
                PreparedStatement pre = conn.prepareStatement(sql);
                JDBCPoolUtil.insert(pre);
                // 释放资源
                JDBCPoolUtil.clear(conn,pre);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        Long endTime1 = System.currentTimeMillis();
        System.out.println("使用连接池耗时:"+ (endTime1 - startTime1) +"毫秒");
    }
}

可以看到每次操作完毕,都归还了连接对象
什么是数据池?-简单的例子_第1张图片

最后将JDBCPoolUtil类中打印的两句话注释掉,比较两种方法的耗时

操作次数 (耗时)不使用连接池 (耗时)使用连接池
10 475毫秒 164毫秒
100 942毫秒 354毫秒
1000 4800毫秒 1719毫秒
10000 34579毫秒 14614毫秒

可以得知,在没有任何其他优化的情况下,使用数据池已经是肉眼可见的快了

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