数据库连接池技术:DBCP和C3P0

1.什么是数据库连接池

已知的方法是需要访问数据库的时候进行一次数据库的连接,对数据库操作完之后再释放这个连接,通常这样业务是缺点很明显的:

用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出,拓机。

所有,有了数据库连接池的概念,在程序启动的时候,就自动创建几个数据库连接,放在一个池子里(集合),需要用的时候从这个池子里面获取

连接池技术

连接池技术有两种,一种是自定义连接池,但是这样使用过于繁琐,不可能在每个项目都都重新定义一个连接池。第二种是使用一些开源组件,常用的数据库连接池组件有:DBCP组件和C3P0组件,下面分别讲解

2.自定义连接池

自定义连接池程序思路:

1.指定“初始化连接数目”(假设为3),在app启动的时候,就自行创建

2.指定“最大连接数”(假设为6)

3.指定“当前使用连接个数”(不能超出最大连接数)

代码逻辑:

1.dbPool.java连接池类

2.指定全局参数:初始化数目,最大连接数目,当前连接,连接池集合

3.构造函数:循环创建3个连接

4.写一个创建连接的方法

5.获取连接

  • 判断:池中有连接,直接拿,如果池中没有连接再判断是否达到最大连接数
  • 如果没有达到最大连接数,直接创建新连接,如果已经大多最大连接数,抛出异常

    6.释放连接:连接放回集合中或者连接池已满,可以直接释放掉

代码实现:

实现过程中如果直接使用realeaseConnection(con1);来释放是没有问题的,但是如果使用close()来释放,就需要再对这个方法使用代理方法来监控close方法,如果close方法被调用,则触发另外的命令

如何对Connection对象,生成一个代理对象:

|--Proxy

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h );

ClassLoader loader, 当前使用的类加载器

Class<?>[] interfaces, 目标对象(Connection)实现的接口类型

InvocationHandler h 事件处理器:当执行上面接口中的方法的时候,就会自动触发事件处理器代码,把当前执行的方法(method)作为参数传入。

package db;

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.SQLException;
import java.util.LinkedList; /**
* 自定义连接池,管理连接池
* Created by cenyu on 16-12-18.
*/
public class dbPool {
//初始化变量
private int init_count = 3;//初始化连接池数目
private int max_count = 6;//初始化最大连接数
private int current_count = 0;//记录当前使用连接数
//连接池(存放所有的初始化连接)
private LinkedList<Connection> pool = new LinkedList<Connection>(); //1.构造函数中,初始化连接放入连接池
public dbPool(){
//初始化连接
for (int i = 0; i < init_count; i++) {
//记录当前连接数据
current_count++;
//创建原始的连接对象
Connection con = createConnection();
//把连接加入连接池
pool.addLast(con);
}
} //2.创建一个新的连接的方法
private Connection createConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
//原始目标对象
final Connection con =DriverManager.getConnection("jdbc:mysql://db", "root", "root"); /**********对con对象代理**************/ // 对con创建其代理对象
Connection proxy = (Connection) Proxy.newProxyInstance( con.getClass().getClassLoader(), // 类加载器
//con.getClass().getInterfaces(), // 当目标对象是一个具体的类的时候
new Class[]{Connection.class}, // 目标对象实现的接口 new InvocationHandler() { // 当调用con对象方法的时候, 自动触发事务处理器
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 方法返回值
Object result = null;
// 当前执行的方法的方法名
String methodName = method.getName(); // 判断当执行了close方法的时候,把连接放入连接池
if ("close".equals(methodName)) {
System.out.println("begin:当前执行close方法开始!");
// 连接放入连接池
pool.addLast(con);
System.out.println("end: 当前连接已经放入连接池了!");
} else {
// 调用目标对象方法
result = method.invoke(con, args);
}
return result;
}
}
);
return proxy;
} catch (Exception e) {
throw new RuntimeException(e);
}
} //3. 获取连接
public Connection getConnection(){ // 3.1 判断连接池中是否有连接, 如果有连接,就直接从连接池取出
if (pool.size() > 0){
return pool.removeFirst();
} // 3.2 连接池中没有连接: 判断,如果没有达到最大连接数,创建;
if (current_count < max_count) {
// 记录当前使用的连接数
current_count++;
// 创建连接
return createConnection();
} // 3.3 如果当前已经达到最大连接数,抛出异常
throw new RuntimeException("当前连接已经达到最大连接数目 !");
} //4. 释放连接
public void realeaseConnection(Connection con) {
// 4.1 判断: 池的数目如果小于初始化连接,就放入池中
if (pool.size() < init_count){
pool.addLast(con);
} else {
try {
// 4.2 关闭
current_count--;
con.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
} public static void main(String[] args) throws SQLException {
dbPool pool = new dbPool();
System.out.println("当前连接: " + pool.current_count); // 3 // 使用连接
pool.getConnection();
pool.getConnection();
Connection con4 = pool.getConnection();
Connection con3 = pool.getConnection();
Connection con2 = pool.getConnection();
Connection con1 = pool.getConnection(); // 释放连接, 连接放回连接池
// pool.realeaseConnection(con1);
/*
* 希望:当关闭连接的时候,要把连接放入连接池!【当调用Connection接口的close方法时候,希望触发pool.addLast(con);操作】
* 把连接放入连接池
* 解决1:实现Connection接口,重写close方法
* 解决2:动态代理
*/
con1.close(); // 再获取
pool.getConnection(); System.out.println("连接池:" + pool.pool.size()); // 0
System.out.println("当前连接: " + pool.current_count); // 3
}
}

2.DBCP连接池

开源数据库连接池

在java的web服务器上,都提供了DataSoruce的,即连接池实现的,sun公司规定,如果是自己写的连接池,要实现javax.sql.DataSource接口

目前使用最多的开源数据库连接池有:

  • DBCP 数据库连接池(tomcat)
  • C3P0 数据库连接池(hibernate)

    实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员变成时也应尽量使用这些技术,以提升程序的数据库访问性能

DBCP数据源

DBCP是Apache软件基金组织下的开源连接池实现,使用DBCO数据源

使用的时候需要导入两个jar文件

  • commons-dbcp.jar:连接池的实现
  • commons-pool.jar:连接池实现的依赖库

Tomcat的连接池正是采用该连接池来实现的,该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用

使用方法有两种,一种是硬编码,由于不好维护,所以不推荐,推荐使用第二种用配置文件法。

第二种配置方式实现需要注意点是:配置文件中的key与BaseDataSouce中的属性一致。(去掉set然后第一个字母小写)

代码示例:

package dao;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test; import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; /**
* 测试DBCP数据源的使用方式
* Created by cenyu on 16-12-18.
*/
public class testDBCP { //1.硬编码方式实现连接池
@Test
public void test1() throws SQLException {
//DBCP连接池核心类
BasicDataSource dataSource = new BasicDataSource();
//连接池参数配置:初始化参数,最大连接数/连接字符串,驱动,用户名,密码等
dataSource.setUrl("jdbc:mysql://localhost:3306/db");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("root"); dataSource.setInitialSize(3);//初始化连接数量
dataSource.setMaxActive(6);//最大连接数量
dataSource.setMaxIdle(3000);//最大空闲时间,超过这个时间就会释放 //获取连接
Connection con = dataSource.getConnection();
con.prepareStatement("DELETE FROM Admin WHERE id =2").executeUpdate();
//关闭
con.close();
} //2.【推荐使用】配置方式实现连接池,便于维护
@Test
public void test2() throws Exception {
//加载prop配置文件
Properties prop = new Properties();
//获取文件流
InputStream inputStream=testDBCP.class.getClassLoader().getResourceAsStream("db.properties");
//加载属性配置文件
prop.load(inputStream);
//根据prop配置,直接创建数据源对象
DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
//获取连接
Connection con = dataSource.getConnection();
con.prepareStatement("DELETE FROM Admin WHERE id =4").executeUpdate();
//关闭
con.close();
}
}

3.C3P0连接池

C3P0连接池组件是最常用的连接池技术,Spring框架默认是支持C3P0连接池技术的。

C3P0连接池的核心类:

CombopooledDataSource ;

使用方法:

1.下载,引入jar文件:c3p0-0.9.1.2.jar

2.使用连接池,创建连接

  • a.硬编码方法
  • b.配置方式(xml配置)
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test; import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentNavigableMap; /**
* 使用C3P0连接池技术的两种方法
* Created by cenyu on 16-12-18.
*/
public class testC3P0 { //1.硬编码方式,使用c3p0连接池管理连接
@Test
public void testCode() throws Exception {
//创建连接池核心工具类
ComboPooledDataSource dataSource=new ComboPooledDataSource();
//设置连接参数:url、驱动、用户密码、初始连接数、最大连接数
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(6);
dataSource.setMaxIdleTime(1000); //从连接池对象中,获取连接对象
Connection conn = dataSource.getConnection();
//执行跟新
conn.prepareStatement("DELETE FROM Admin WHERE id=1").executeUpdate();
//关闭
conn.close();
} //2.xml配置方式,使用c3p0连接池管理连接
@Test
public void testXML() throws Exception{
//创建C3P0连接核心工具类
//自动加载src下c3p0的配置文件【c3p0-config.xml】
ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");//使用mysql的配置
//获取连接
Connection conn = dataSource.getConnection();
//执行连接
conn.prepareStatement("delete from Admin where id=3").executeUpdate();
//关闭
conn.close();
}
}

c3p0-config.xml配置文件修改之后放在项目src的根目录下就可以了,编译之后会把这个文件编译到WEB-INF/classes下的

常用的配置文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- This is default config! -->
<default-config>
<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> <!-- This is my config for mysql-->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password"></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>
</named-config> <!-- This is my config for oracle -->
<named-config name="oracle">
<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
<property name="jdbcUrl">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="user">scott</property>
<property name="password">liang</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>
</named-config>
</c3p0-config>

.数据库连接池技术:DBCP和C3P0的更多相关文章

  1. 开源的连接池技术DBCP和C3P0

    概述: Sun公司约定: 如果是连接池技术,需要实现一个接口! javax.sql.DataSource;   相关jar包和资料下载 1.1  DBCP连接池: l  DBCP 是 Apache 软 ...

  2. JDBC(三)数据库连接池(DBCP、C3P0)

    前言 这段时间状态有一点浮躁,希望自己静下心来.还有特别多的东西还没有学懂.需要学习的东西非常的多,加油! 一.JDBC复习 Java Data Base Connectivity,java数据库连接 ...

  3. Java Web(九) JDBC及数据库连接池及DBCP,c3p0,dbutils的使用

    DBCP.C3P0.DBUtils的jar包和配置文件(百度云盘):点我下载 JDBC JDBC(Java 数据库连接,Java Database Connectify)是标准的Java访问数据库的A ...

  4. JDBC数据库连接池技术

    在JDBC中,获得连接或释放资源是非常消耗系统资源的两个过程,为了解决此类性能问题,通常采用连接池技术,来共享连接.这样我们就不需要每次都创建连接.释放连接了,这些操作都交给了连接池. 用池的概念来管 ...

  5. Java使用独立数据库连接池(DBCP为例)

    目前,绝大多数的软件系统都会使用数据库,而在软件构建起来之后,访问数据库又成为软件系统性能的短板(I/O操作).一般来说一次访问数据库就需要一个数据库连接.而每次创建数据库连接都需要访问,分配空闲资源 ...

  6. Java学习:数据库连接池技术

    本节内容 数据库连接池 Spring JDBC : JDBC Template 数据库连接池 1.概念:其实就是一个容器(集合),存放数据库连接的容器 当系统初始化好后,容器中会申请一些连接对象,当用 ...

  7. java数据库连接池技术原理(浅析)

    在执行数据库SQL语句时,我们先要进行数据连接:而每次创建新的数据库的连接要消耗大量的资源,这样,大家就想出了数据库连接池技术.它的原理是,在运行过程中,同时打开着一定数量的数据库连接,形成数据连接池 ...

  8. 【Java】数据库连接池技术

    JDBC的问题 在程序中,我们经常要建立与数据库的连接,之后再关闭这个连接.我们知道,数据库连接对象的创建是比较消耗系统性能的,这些频繁的操作势必会消耗大量的系统资源.因此我们需要采用更高效的数据库访 ...

  9. 基于JDBC的数据库连接池技术研究与应用

    引言 近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的3层开 ...

随机推荐

  1. Python标准模块--import

    1 模块简介 作为一个Python初学者,你首先要学会的知识就是如何引入其它模块或者包.但是,我发现有些开发者虽然使用Python很多年,依然不了解Python引入机制的灵活性.这篇文章,我们就会研究 ...

  2. 《JS设计模式笔记》构造函数和工厂模式创建对象

    工厂模式 function createPerson (name,age,job) { var o=new Object(); o.name=name; o.age=age; o.job=job; o ...

  3. Mina、Netty、Twisted一起学(八):HTTP服务器

    HTTP协议应该是目前使用最多的应用层协议了,用浏览器打开一个网站就是使用HTTP协议进行数据传输. HTTP协议也是基于TCP协议,所以也有服务器和客户端.HTTP客户端一般是浏览器,当然还有可能是 ...

  4. 对C语言islower、isupper、isdigit函数的测试

    今天朋友问起了这三个函数,我就帮忙测试了下,测试后发现谭浩强第四版课本附录上上讲的不是很严谨. 我们先看下这三个函数介绍: 谭浩强第四版课本附录第396页上这样介绍: 函数名 函数原型 功能 返回值 ...

  5. 原生JS实现全屏切换以及导航栏滑动隐藏及显示——重构前

    思路分析: 向后滚动鼠标滚轮,页面向下全屏切换:向前滚动滚轮,页面向上全屏切换.切换过程为动画效果. 第一屏时,导航栏固定在页面顶部,切换到第二屏时,导航条向左滑动隐藏.切换回第一屏时,导航栏向右滑动 ...

  6. Aspose.Cells导出Excel(1)

    利用Aspose.Cells导出excel 注意的问题 1.DataTable的处理 2.进行编码,便于中文名文件下载 3.别忘了Aspose.Cells.dll(可以自己在网上搜索) public ...

  7. JavaWeb_day01_HTTP_Servlet

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! JavaWeb_day01 HTTP协议 HTTP(H ...

  8. intellij idea 15 修改基础配置加载路径

    一.概述 intellij idea 15 默认配置的启动加载路径是"C:\Users\Administrator.IntelliJIdea15",这样会导致占用C盘的空间越来越多 ...

  9. .NET Core 2.0版本预计于2017年春季发布

    英文原文: NET Core 2.0 Planned for Spring 2017 微软项目经理 Immo Landwerth 公布了即将推出的 .NET Core 2.0 版本的细节,该版本预计于 ...

  10. Struts2框架深入详解版

    一.认识Struts2 1. 什么是Web框架? 1.1  模型1 1.2  模型2 和MVC 1.3   Web框架的诞生 2. Struts1 到Struts2 2.1 其他 Web框架 2.2 ...