Java 数据库连接池笔记
JDBC
Java 数据库连接(Java Database Connectivity,简称JDBC)是 Java 语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
JDBC 的创建
使用 JDBC 访问数据库的流程:
- 加载 JDBC 驱动
- 连接数据库
- 执行 SQL 查询
- 从结果集中提取数据
- 处理结果集
- 清理环境,关闭所有的数据库资源,释放内存
关于 JDBC 更详细的介绍与使用:Java-MySQL连接
JDBC 的缺点
熟悉 JDBC 编程的,我们知道它存在很多缺点,如:
- 数据库连接,使用时创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响了数据库的性能。
- 将 sql 语句硬编码到java代码中,如果 sql 语句的修改,需要重新编译java代码,不利于系统的维护
- 向 preparedStatement 中设置参数,对占位符位置和参数值,硬编码在代码中,不利于系统的维护。
- 从 resultSet 中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统的维护。
针对上述缺点,我们对应的解决方案:
- 问题1:使用数据库的连接池管理数据库的连接。
- 问题2:将 sql 语句配置到 xml 配置文件中,即使 sql 变化,不需要对 java 进行重新编译
- 问题3:将 sql 语句和参数值配置到 xml 中
- 问题4:将查询的结果自动的映射的 java 的对象
总的来说,我们主要会采用数据库连接池解决数据库频繁链接与释放问题,采用配置文件解决 sql 语句硬编码问题。
数据库连接池
连接池技术的核心思想是:连接复用,通过建立一个数据库连接池以及一套连接使用、分配、管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。另外,由于对 JDBC 中的原始连接进行了封装,从而方便了数据库应用对于连接的使用(特别是对于事务处理),提高了开发效率,也正是因为这个封装层的存在,隔离了应用的本身的处理逻辑和具体数据库访问逻辑,使应用本身的复用成为可能。
连接池的操作:
- 建立数据库连接池对象(服务器启动)。
- 按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
- 对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。
- 存取数据库。
- 关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。
- 释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。
自定义数据库连接池
大致了解了数据库连接池的原理与创建方法,我们可以自己编写一个数据库连接池,而编写连接池需实现javax.sql.DataSource
接口。DataSource
接口中定义了两个重载的getConnection
方法:
Connection.getConnection()
Connection.getConnection(String username, String password)
自定义一个类,实现DataSource接口,并实现连接池功能的步骤:
- 在自定义类的构造函数中批量创建Connection,并把创建的连接保存到一个集合对象中(LinkedList)。
- 在自定义类中实现Connection.getConnection方法,让getConnection方法每次调用时,从集合对象中取出一个Connection返回给用户。
- 当用户使用完Connection,不能调用Connection.close()方法,而要使用连接池提供关闭方法,即将Connection放回到连接池之中(把Connection存入集合对象中)。
注:Connection对象应保证将自己返回到连接池的集合对象中,而不要把Connection还给数据库。
实际编程时我们并不需要自己编写连接数据库代码,有一些开源组织提供了数据库连接池的实现,我们只要会使用即可。在我实习的公司,主要使用以下两种开源数据库连接池:
- C3P0 数据库连接池
- DBCP 数据库连接池
为此,就这两种数据库连接池,我做一简单的介绍。
C3P0 数据库连接池
C3P0 是一个开源的 JDBC 连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前使用它的开源项目有Hibernate,Spring 等。
C3P0 所需 JAR 包: c3p0-0.9.2.1.jar 和 mchange-commons-java-0.2.3.4.jar
配置文件常用的属性:
####### c3p0 #######
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/test
c3p0.user=xxxx
c3p0.password=xxxxx
c3p0.initialPoolSize=10 //初始化连接数
c3p0.minPoolSize=10 //最大连接数
c3p0.maxPoolSize=30 //最小连接数
c3p0.maxIdleTime=30 //最大空闲时间 => 这就是为什么C3P0有自动回收的原因
c3p0.acquireIncrement=5 //新增连接数
当创建连接池时,一次性创建initialPoolSize 个连接,当连接使用完一次性创建 acquireIncrement 个连接,连接最大数量 maxPoolSize ,当连接池连接数量大于 minPoolSize ,经过 maxIdleTime 连接没有使用, 该连接将被释放。
C3P0 连接创建方式主要分为:配置文件形式和硬编码形式,这点和 DBCP 数据库连接池非常相似,唯一不同的就是配置文件命名规范不同,C3P0 配置文件必须命名为 c3p0-config.xml 或 c3p0-config.properties ,并且放在 src 目录下,而 DBCP 没有这样的要求。
DBCP 数据库连接池
DBCP(DataBase connection pool), 数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 默认使用的连接池组件。
DBCP 需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar
配置文件常用的属性:
####### dbcp #######
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=xxxx
password=xxxxx
initialSize=10
# maxActive=10 // dbcp2中已将MaxActive设置为MaxTotal
maxTotal=30 // 可以在这个池中同时被分配的有效连接数的最大值,如设置为负数,则不限制
maxIdle=10 // 可以在池中保持空闲的最大连接数,超出设置值之外的空闲连接将被回收,如设置为负数,则不限制
minIdle=5 // 可以在池中保持空闲的最小连接数,超出设置值之外的空闲连接将被创建,如设置为0,则不创建
关于 C3P0 和 DBCP 配置文件更详细的说明,请自行了解。Demo 可参见我的GitHub仓库,后续会补充测试代码。
C3P0 与 DBCP 区别
- C3P0 自动回收空闲连接
- 主要因为
maxIdleTime
属性,当连接池连接数量大于minPoolSize
,经过maxIdleTime
连接没有使用, 该连接将被释放
- C3P0 拥有 3 种配置方法,DBCP 拥有 2 种配置方法
- 对数据连接的处理方式,C3P0 提供最大空闲时间,DBCP 提供最大连接数
- 前者当连接超过最大空闲连接时间时,当前连接就会被断掉。DBCP 当连接数超过最大连接数时,所有连接都会被断开。