JDBC连接池

10 篇文章 0 订阅


JDBC操作中,连接数据库是必备的,可以通过连接池提前创建数据库连接,方便后续调用

原理

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

第一次访问时需要建立连接,但是之后的访问均会复用之前创建的连接,直接执行SQL语句


作用

  1. 较少了网络开销
  2. 实现了系统性能实质的提升
  3. 无TIME_WAIT状态

实现方式

  1. 自定义连接池
  2. DBCP连接池
  3. C3P0连接池
  4. Druid连接池

tips:
我们可以通过自定义的方式实现连接池,分析连接池类应该包含特定的属性和方法
DBCP连接池、C3P0连接池、Druid连接池可以直接使用

主要参数

  • 初始化连接数
    连接池启动时创建的初始化数据库连接数量
  • 最小连接数
    连接池一直保持的数据库连接
    如果应用程序对数据库连接的使用量不大,将会大量浪费数据库连接资源
  • 最大连接数
    连接池能申请的最大连接数
    如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
  • 最大空闲时间/最大等待时间
    当没有可用连接时,连接池等待连接被归还的最大时间
    超过时间抛出异常,可设置参数为0或者负数使得无限等待(根据不同连接池配置)
  • 获取连接超时时间
  • 超时重试连接次数

已经定义好的连接池的主要参数:

DBCPC3P0Druid
初始化连接数initialSize(0)initialPoolSize(3)initialSize(0)
最小连接数minldle(0)minPoolSize(3)minldle(0)
最大连接数maxTotal(8)maxPoolSize(15)maxActive(8)
最大等待时间maxWaitMillis(毫秒)maxIdelTime(0秒)maxWait(毫秒)

  • tips
    DBCP连接池的配置中,有一个maxIdle属性,表示最大空闲连接数,超过的空闲连接将被释放,默认值为8
    maxIdle属性在Druid连接池已不再使用,配置了也没有效果
    c3p0连接池没有maxIdle属性

工作步骤

  1. 连接池的建立
  2. 连接池中连接的使用管理
  3. 连接池的关闭
  • tips
    1、数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接
    2、当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错
    3、如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接
    4、连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用

自定义连接池

了解思路,代码无需自己实现

基本思想

系统初始化时,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象

使用完毕后,用户并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用

连接的建立、断开都由连接池自身来管理
↓↓↓↓↓↓
可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等,也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等

代码实现

将连接数据库的信息放到集合中

属性: 集合 放置Connection
方法:获取连接方法、回收连接方法

1. 普通连接池

  • 定义集合,通过list链式存储使得数据有序
	static LinkedList<Connection> list = new LinkedList<Connection>();
  • 静态代码块,初始化10个连接
   static{
        for (int i = 0; i < 10; i++) {
            //JDBCUtils类是自定义类,封装了连接数据库的信息代码
            Connection connection = JDBCUtils.newInstance().getConnection();
            list.add(connection);
        }
    }

  • 从连接池子中获取连接的方式
 	public static Connection getConnection(){
        if (list.isEmpty()) {
            //JDBCUtils类是自定义类,封装了连接数据库的信息代码
            Connection connection = JDBCUtils.newInstance().getConnection();
            list.addLast(connection);
        }
        Connection conn = list.removeFirst();//取出第一个
        return conn;
    }
  • 返回到连接池子中
public static void addBack(Connection conn){
        if (list.size() >= 10) {//超过连接数
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            list.addLast(conn); //添加
        }
    }
  • 获取连接池子中连接数量
    public static int getSize(){
        return list.size();
    }

2. 规范实现连接池

Java为连接池实现提供了一个规范(接口):DataSource接口

实现DataSource接口没有提供回收链接方法,因此使用装饰者模式

  • 将被装饰者导入
public class MyConnection implements Connection {
    private Connection conn;
    private LinkedList<Connection> list;
    public MyConnection(Connection conn, LinkedList<Connection> list) {
        super();
        this.conn = conn;
        this.list = list;
    }
    
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return conn.unwrap(iface);
    }
    
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return conn.isWrapperFor(iface);
    }
    
    @Override
    public Statement createStatement() throws SQLException {
        return conn.createStatement();
    }
    
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }
    
    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return null;
    }
    
    @Override
    public String nativeSQL(String sql) throws SQLException {
        return null;
    }
    
    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
    }
    
    @Override
    public boolean getAutoCommit() throws SQLException {
        return false;
    }
    
    @Override
    public void commit() throws SQLException {
        conn.commit();
    }
    
    @Override
    public void rollback() throws SQLException {
        conn.rollback();
    }
    
    @Override
    public void close() throws SQLException {
        list.addLast(conn);
    }
    
}
  • 创建基于规范实现的连接池
public class DataSourcePool implements DataSource {
    static LinkedList<Connection> list = new LinkedList<Connection>();
    
    static{
        for (int i = 0; i < 10; i++) {
            Connection connection = JDBCUtils.newInstance().getConnection();
            list.add(connection);
        }
    }
    
    public static int getSize(){
        return list.size();
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        Connection conn = list.removeFirst();
        MyConnection conn1 = new MyConnection(conn, list);
        return conn1;
    }
    
    @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;
    }
    
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }
    
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
    
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }
    
}

DBCP连接池

需要的jar包

mysql-jdbc.jar
commons-dbcp.jar
commons-pool.jar

DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池

DBCP可以直接的在应用程序中使用,Tomcat的数据源使用的为DBCP

代码实现

以DBUtil类中封装的方法为例:

	//定义需要的工具类对象(变量定义)
    protected Connection connection = null;
    protected PreparedStatement pps = null;//后续都是用预状态通道来实现
    protected ResultSet rs = null;//结果集
    protected int count = 0;//受影响的行数

    //登录的用户名和密码
    private static String username;
    private static String password;
    private static String url;
    private static String driverName;
    private static BasicDataSource basicDataSource = new BasicDataSource();

    //加载驱动
    static {
        /*
        try {
            ResourceBundle bundle = ResourceBundle.getBundle("db");//参数只写属性文件名,不需要写后缀
            driverName = bundle.getString("driver");
            url = bundle.getString("url");
            username = bundle.getString("username");
            password = bundle.getString("password");

            Class.forName(driverName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        */

        //DBCP
        ResourceBundle bundle = ResourceBundle.getBundle("db");//参数只写属性文件名,不需要写后缀
        driverName = bundle.getString("driver");
        url = bundle.getString("url");
        username = bundle.getString("username");
        password = bundle.getString("password");

        basicDataSource.setUsername(username);
        basicDataSource.setPassword(password);
        basicDataSource.setUrl(url);
        basicDataSource.setDriverClassName(driverName);

        //设置初始大小,初始化20个连接
        basicDataSource.setInitialSize(20);
    }


    //获得连接
    protected Connection getConnection() {
        try {
        	/*
            connection = DriverManager.getConnection(url, username, password);
            */
            connection = basicDataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

C3P0连接池

c3p0是开源的JDBC连接池,在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection和Statement池的DataSources对象

c3p0与dbcp区别:

c3p0dbcp
有自动回收空闲连接功能没有自动回收空闲连接的功能
不需要手动设置需要手动设置配置文件

需要的jar包

c3p0-0.9.1.2.jar
mysql-connector-java-5.0.8.jar

实现方式

1、手动设置工具类ComboPooledDataSource

2、加载配置文件

在src下创建文件c3p0-config.xml

<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <!-- 基本配置 -->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT</property>
        <property name="user">root</property>
        <property name="password">123456</property>
        <!--扩展配置-->
        <!-- 连接超过30秒报错-->
        <property name="checkoutTimeout">30000</property>
        <!--30秒检查空闲连接 -->
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">10</property>
        <!-- 30秒不适用丢弃-->
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config>
</c3p0-config>

代码实现

  • 创建对象
    //定义需要的工具类对象(变量定义)
    protected Connection connection = null;
    protected PreparedStatement pps = null;//后续都是用预状态通道来实现
    protected ResultSet rs = null;//结果集
    protected int count = 0;//受影响的行数

    //登录的用户名和密码
    private static String username;
    private static String password;
    private static String url;
    private static String driverName;
    
    //C3PO
    private static ComboPooledDataSource comboPooledDataSource =new ComboPooledDataSource();
  • 获得连接
	protected Connection getConnection() {
        try {
			//connection = DriverManager.getConnection(url, username, password);
			//connection = basicDataSource.getConnection();
            connection = comboPooledDataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

☆Druid连接池

德鲁伊连接池,是目前比较流行的高性能的、分布式列存储的OLAP框架(具体来说MOLAP)

阿里出品,淘宝和支付宝专用数据库连接池

Druid不仅仅是数据库连接池,还包含一个ProxyDriver(代理驱动)、一系列内置的JDBC组件库、一个SQL Parser(sql解析器),支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等

通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如分库分表、审计等,Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

特点

1. 亚秒级查询

Druid提供了快速的聚合能力以及亚秒级的OLAP查询能力,多租户的设计,是面向用户分析应用的理想方式

2. 实时数据注入

Druid支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性

3. 可扩展的PB级存储(存储量大)

Druid集群可以很方便的扩容到PB的数据量,每秒百万级别的数据注入,即使在加大数据规模的情况下,也能保证时其效性

4. 多环境部署

Druid既可以运行在商业的硬件上,也可以运行在云上,可以从多种数据系统中注入数据,包括hadoop、spark、kafka、storm、samza等

5. 丰富的社区

druid拥有丰富的社区,供交流学习

需要的jar包

druid-1.0.9.jar

代码实现

tips:
在Druid连接池的配置中,driverClassName可配可不配,如果不配置会根据url自动识别dbType(数据库类型),然后选择相应的driverClassName

创建对象

    protected Connection connection = null;
    protected PreparedStatement pps = null;//后续都是用预状态通道来实现
    protected ResultSet rs = null;//结果集
    protected int count = 0;//受影响的行数

    //登录的用户名和密码
    private static String username;
    private static String password;
    private static String url;
    private static String driverName;
    //DBCP
    //private static BasicDataSource basicDataSource = new BasicDataSource();
    //C3PO
    //private static ComboPooledDataSource comboPooledDataSource =new ComboPooledDataSource();
    
    //Druid
    private static DruidDataSource druidDataSource = new DruidDataSource();

加载驱动

static {
        /*
        try {

//            优化方法一:
//            InputStream inputStream = DBUtils.class.getClassLoader().getResourceAsStream("db.properties");
//            Properties properties = new Properties();
//            properties.load(inputStream);
//            driverName = properties.getProperty("driver");
//            url = properties.getProperty("url");
//            username = properties.getProperty("username");
//            password = properties.getProperty("password");

            ResourceBundle bundle = ResourceBundle.getBundle("db");//参数只写属性文件名,不需要写后缀
            driverName = bundle.getString("driver");
            url = bundle.getString("url");
            username = bundle.getString("username");
            password = bundle.getString("password");

            Class.forName(driverName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        */


        //DBCP
        /*
        ResourceBundle bundle = ResourceBundle.getBundle("db");//参数只写属性文件名,不需要写后缀
        driverName = bundle.getString("driver");
        url = bundle.getString("url");
        username = bundle.getString("username");
        password = bundle.getString("password");

        basicDataSource.setUsername(username);
        basicDataSource.setPassword(password);
        basicDataSource.setUrl(url);
        basicDataSource.setDriverClassName(driverName);

        //设置初始大小,初始化20个连接
        basicDataSource.setInitialSize(20);
        */

        //C3P0

        //Druid
        ResourceBundle bundle = ResourceBundle.getBundle("db");//参数只写属性文件名,不需要写后缀
        //加载属性文件
        driverName = bundle.getString("driver");
        url = bundle.getString("url");
        username = bundle.getString("username");
        password = bundle.getString("password");
        
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverName);
    }

获得连接

    protected Connection getConnection() {
        try {
//            connection = DriverManager.getConnection(url, username, password);
//            connection = basicDataSource.getConnection();
//            connection = comboPooledDataSource.getConnection();
            connection = druidDataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selcouther

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值