连接池概述
一. 为什么要用连接池技术
传统数据库访问方式:一次数据库访问对应一个物理连接,每次操作数据库都要打开、关闭该物理连接, 系统性能严重受损。
解决办法:数据库连接池技术。
系统初始运行时,主动建立足够的连接,组成一个池.每次应用程序请求数据库连接时,无需重新打开连接,而是从池中取出已有的连接,使用完后,不再关闭,而是归还。
二. 连接池的组成
1. 连接池的建立;
2. 连接池中连接的使用管理;
3. 连接池的关闭。
三. 连接池的核心思想
连接复用。通过建立一个数据库连接池以及一套连接使用、分配、管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
1. 连接池的建立
在系统初始化时,根据相应的配置,创建连接并放置在连接池中,以便需要使用时能从连接池中获取。可以避免连接随意的建立、关闭造成的开销。
2. 连接池中连接的使用管理
采用的方法是:Reference Counting(引用记数)。该模式在复用资源方面应用的非常广泛,把该方法运用到对于连接的分配释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。
(1)当客户请求数据库连接时,首先查看连接池中是否有空闲连接(指当前没有分配出去的连接)。如果存在空闲连接,则把连接分配给客户并作相应处理(即标记该连接为正在使用,引用计数加1)。如果没有空闲连接,则查看当前所开的连接数是不是已经达到maxConn(最大连接数),如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的maxWaitTime(最大等待时间)进行等待,如果等待maxWaitTime后仍没有空闲连接,就抛出无空闲连接的异常给用户。
(2)当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就删除该连接,并判断当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。
好处:保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。
3. 连接池的关闭
当应用程序退出时,关闭连接池,把在连接池建立时向数据库申请的连接对象统一归还给数据库(即关闭所有数据库连接)。
几大主流连接池的使用
一. dbcp(Database Connection Pool)
(一)dbcp连接池的相关认识
DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。
(二)所需jar包
2. 提交属性
3. 连接属性
注意:针对负载比较高的应用,最好设置maxIdle接近于maxTotal,例如设置的数量为maxTotal-1甚至等于maxTotal,或者无限制。
(四)两种方式得到数据源
方式一:
配置文件:dbcp.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/stuinformation?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
initialSize=5
maxTotal=10
工具实现类:
public class JdbcUtils {
// 定义BasicDataSorce的父类接口的形式,获得ds的参数
private static BasicDataSource ds;
static {
try {
//创建一个properties容器
Properties pro = new Properties();
//使用类加载器获取properties文件内容的流对象
InputStream stream = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
//加载字节输入流
pro.load(stream);
//关闭流
stream.close();
//创建BasicDataSource对象
ds = new BasicDataSource();
ds.setDriverClassName(pro.getProperty("jdbc.driverClassName"));
ds.setUrl(pro.getProperty("jdbc.url"));
ds.setUsername(pro.getProperty("jdbc.username"));
ds.setPassword(pro.getProperty("jdbc.password"));
ds.setInitialSize(Integer.parseInt(pro.getProperty("initialSize")));
ds.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
} catch (Exception e) {
e.printStackTrace();
}
}
//获得数据库连接对象
public static BasicDataSource getDataSource() {
return ds;
}
// 获得与指定数据库的连接
public static Connection getConnection(){
Connection conn = null;
try{
conn = ds.getConnection();
}catch(Exception e){
e.printStackTrace();
}
return conn;
}
}
注意:dbcp.properties文件中的key与资源文件中的参数不一致,则需要先创建一个数据源BasicDataSource ds = new BasicDataSource();,然后给相应的属性赋setXXX。
方式二:
配置文件:db.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/stuinformation?characterEncoding=utf-8
username=root
password=root
initsize=1
maxtotal=10
maxwait=5000
maxidle=10
minidle=1
工具实现类:
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
/*
*对应的配置文件是:db.properties
*
* 使用DBCP连接池技术管理数据库连接
*/
public class DBCPUtil {
//数据库连接池
private static DataSource dbcp;
//为不同线程管理连接
private static ThreadLocal th1;
//通过配置文件来获取数据库参数
static{
try{
Properties pro = new Properties();
InputStream stream = DBCPUtil.class.getClassLoader().getResourceAsStream("db.properties");
//加载字节输入流
pro.load(stream);
//关闭流
stream.close();
//1.初始化连接池
//BasicDataSource 是dbcp的核心连接池 BasicDataSource 实现了Datasource这个接口
dbcp = BasicDataSourceFactory.createDataSource(pro);
//初始化本地线程
th1 = new ThreadLocal();
}catch(Exception ex){
ex.printStackTrace();
}
}
/*获得数据库连接
* @return
* @SQLException
* */
public static Connection getConnection(){
Connection conn=null;
try{
conn=dbcp.getConnection();
th1.set(conn);
}catch(Exception e){
e.printStackTrace();
}
return conn;
}
/*
* 关闭数据库连接
* */
public static void closeConn(){
Connection conn = th1.get();
try{
if(conn!=null){
/*
*通过连接池获取Connection对象,然后调用close方法,实际上并没有将连接关闭,而是归还
* 了Connection连接对象
* */
conn.close();
th1.remove();
}
}catch(Exception ex){
ex.printStackTrace();
}
}
}
注意:db.properties文件中的key与资源文件中规定的名字一致,则可以使用DataSource dbcp = BasicData SourceFactory.createDataSource(Properties pro);的方式得到数据源。
重要:获取了Connection对象后,对于增删改查操作,正常的使用jdbc去写。!!
二. C3P0连接池
(一)C3P0连接池的相关认识
是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring。
优点:
1) 资源重用:避免了频繁创建,减少大量不必要的性能开销,增加了系统运行环境的平稳性。
2)更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
3)新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源。
4)统一的连接管理,避免数据库连接泄露:在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
(三)c3p0连接池的使用
c3p0连接池jar下载地址: https://sourceforge.net/projects/c3p0/或:http://mvnrepository.com/中搜索。
需要使用的jar包:
c3p0工具类(使用xxx.properties文件)
注意:数据源的获取: new ComboPooledDataSource()
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3p0Utils {
private static ComboPooledDataSource cpds = null;
static {
try {
/* 加载配置文件 */
Properties pro = new Properties();
// 用类加载器的方式加载配置文件
InputStream stream = C3p0Utils.class.getClassLoader().getResourceAsStream("c3p0.properties");
// 将资源放入properties容器中
pro.load(stream);
stream.close();
/* 创建数据源对象 */
cpds = new ComboPooledDataSource();
System.out.print(cpds);
cpds.setDriverClass(pro.getProperty("/c3p0.driverClass"));
cpds.setJdbcUrl(pro.getProperty("c3p0.jdbcUrl"));
cpds.setUser(pro.getProperty("c3p0.user"));
cpds.setPassword(pro.getProperty("c3p0.password"));
} catch (IOException | PropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* 获取Connection连接对象 */
public static Connection getConn() throws SQLException {
return cpds.getConnection();
}
}
三. Druid连接池
(一)Druid连接池的相关认识
DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOO等DB池的 优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。
(二)Druid连接池的使用
1.导入jar包 druid-1.1.10.jar
2.定义配置文件 druid.properties 。名字可以任意,位置可以任意,通常在src下
3.加载配置文件
4.使用DruidDataSourceFactory的createDataSource获得连接池对象
5.创建connection对象
6.创建要执行的sql语句
7.创建Statement/PreparedStatement对象执行sql语句
8.获得ResultSet结果集对象(查询)或者返回影响的行数
9.关闭连接,释放资源
(三)工具类的创建
1.使用静态代码块加载配置文件
2.使用DruidDataSourceFactory获得DataSource对象
3.创建static方法返回Connection对象
4.创建static方法返回DataSouce对象
5.关闭连接
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mysql.jdbc.PreparedStatement;
/*druid连接池的使用*/
public class DruidUtils {
//数据源对象
private static DataSource ds;
//connection连接对象
private static Connection conn;
static{
try {
/*加载配置文件*/
Properties pro = new Properties();
InputStream stream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(stream);
/*获得数据库连接池对象*/
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
/*获取连接对象*/
public static Connection getConn() throws Exception {
return ds.getConnection();
}
/*关闭连接,释放资源*/
public static void close(Connection conn,PreparedStatement ps,ResultSet rs){
try{
if(rs!=null){
rs.close();
}
if(ps!=null){
ps.close();
}
if(conn!=null){
conn.close();
}
}catch (Exception e) {
e.printStackTrace();
}
}
/*获取连接池*/
public static DataSource getDaSource(){
return ds;
}
}
(四)xxx.properties配置文件
1. 数据源信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/stuinformation?characterEncoding=utf-8
username=root
password=root
#初始化连接数
initialSize=1
最大连接数
maxActive=10
最小连接数
minIdle=1
最大等待时间(毫秒)
maxWait=3000
已被取出的连接超过时间限制是否回收
removeAbandoned=true
已被取出的连接超过此时间限制未被利用会被回收的秒数
removeAbandonedTimeout=180
Destory线程会检测连接的间隔时间(毫秒)
timeBetweenEvictionRunsMillis=3000
连接池中未被取出的连接超过此时间限制会被关闭(毫秒)
minEvictableIdleTimeMillis=4000
用作测试的sql语句,用于检测连接是否可以
validationQuery=SELECT 1
申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测
testWhileIdle=true
申请连接时执行validationQuery检测连接是否有效,会降低性能
testOnBorrow=false
归还连接时执行validationQuery检测连接是否有效,会降低性能
testOnReturn=false
是否缓存预编译sql语句
poolPreparedStatements=false
缓存预编译sql语句的最大数量
maxPoolPreparedStatementPerConnectionSize=100