转自:http://www.cnblogs.com/ysw-go/

JDBC数据库连接池的必要性

一、在使用开发基于数据库的web程序时,传统的模式基本是按一下步骤:

1)在主程序(如servlet/beans)中建立数据库连接

2)进行sql操作

3)断开数据库连接

二、这种模式开发,存在的问题:

1)普通的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都要将Connection加载进内存中,再验证用户名和密码(得花费0.05s~1s的时间).需要数据库连接的时候,就向数据库要求一个,执行完成后就断开连接。这样的方式将消耗大连的时间和资源。数据库的连接资源并没有得到很好的重复利用。若同时有几百人甚至几千人同时在线,频繁的进行数据库连接将占用很多的系统资源,严重的甚至会造成服务器的崩溃。

2)对于每一次数据库连接,使用完成后都要断开。否则,如果程序出现异常而未能关闭,将导致数据库系统的内存泄露,并最终导致重启数据库。

3)这种开发不能控制被创建的连接对象数,系统资源被毫无顾忌的分配出去,如连接过多,也可能导致内存泄露,服务器崩溃

数据库连接池(connection pool)

1)为了解决传统开发中的数据库连接问题,可以采用数据库连接池技术。

2)数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”,预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需要从“缓冲池”中取出一个,使用完毕之后再放回去。

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

4)数据库连接池在初始化的时候将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。

连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序想连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待序列中.

数据库连接池(connection pool)的工作原理

数据库连接池(connection pool)的优点

1) 资源重用 
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量);
2) 更快的系统响应速度 
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间;
3) 新的资源分配手段 
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年前也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源;
4) 统一的连接管理,避免数据库连接泄漏 
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。一个最小化的数据库连接池实现;

两种开源的数据库连接池
1)JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由服务器(Weblogic,WebSphere,Tomcat)提供实现
--DBCP数据库连接池(Tomcat内置的数据库连接池)
--C3P0数据库连接池(Hibernate推荐使用的数据库连接池,性能不错)
2)DataSource通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把DataSource称为连接池。
DBCP数据库连接池
方式一:
使用DBCP数据库连接池的步骤

* 1.加入JAR包(2个)
* commons-dbcp2-2.1.1.jar
* Commons-pool.jar
* 2.创建数据库连接池
* 3.为数据源实例指定必须的属性
* 4.从数据源中获取数据库连接

具体代码实现:

 1 @Test
 2     public void testDBCP() throws Exception{
 3         DataSource dataSource=null;
 4         //1.创建DBCP数据源实例
 5         dataSource=new BasicDataSource();
 6         //2.为数据源实例指定必须的属性
 7         ((BasicDataSource) dataSource).setUsername("root");
 8         ((BasicDataSource) dataSource).setPassword("123456");
 9         ((BasicDataSource) dataSource).setUrl("jdbc:mysql://localhost:3306/atguigu");
10         ((BasicDataSource) dataSource).setDriverClassName("com.mysql.jdbc.Driver");
11         //3.指定数据源一些可选的属性(可以看下载的Jar包中的index.html)API文档
12         /*
13          * maxIdle,最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。
14            MaxActive,连接池的最大数据库连接数。设为0表示无限制。
15            maxWait ,最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制
16                                 【温馨提示】:pool2中修改如下:
17                     maxActive  ==>  maxTotal
18                     maxWait ==> maxWaitMillis
19          */
20         //1).指定数据库连接池中初始化连接的个数
21         ((BasicDataSource) dataSource).setInitialSize(10);
22         //2).指定数据库连接池中最大连接的个数:同一时刻可以同时向数据库申请的数据库连接
23         ((BasicDataSource) dataSource).setMaxTotal(5);
24         //3).指定数据库连接池中最小连接的个数:在连接池中保存的最小空闲连接的数量
25         ((BasicDataSource) dataSource).setMinIdle(5);
26         //4).指定数据库连接池分配连接的最长时间,单位为毫秒,超出改时间将抛出异常
27         ((BasicDataSource) dataSource).setMaxWaitMillis(1000*5);
28         //4.从数据源中获取数据库连接
29
30         Connection connection=dataSource.getConnection();
31         System.out.println(connection.getClass());
32
33     }

方式二:

使用DBCP数据库连接池的步骤

* 1.加载dbcp的properties配置文件
* 配置文件中的键值对需要来自BasicDataSource这个类的属性
* 2.调用BasicDataSourceFactory的createDataSource方法
* 创建DataSource实例
* 3.从DataSource中获取数据库连接

dbcp.properties文件内容如下:

driver=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/atguigu
user=root
password=123456
initialSize=10
maxTotal=50
minIdle=5
maxWaitMillis=5000

具体代码实现:

 1 @Test
 2     public void testDBCPWithDataSourceFactory() throws Exception{
 3         Properties properties=new Properties();
 4         InputStream inputStream=JDBCTest.class.getClassLoader()
 5                 .getResourceAsStream("dbcp.properties");
 6         properties.load(inputStream);
 7         DataSource dataSource=
 8                 BasicDataSourceFactory.createDataSource(properties);
 9         System.out.println(dataSource.getConnection());
10
11         BasicDataSource basicDataSource=
12                 (BasicDataSource) dataSource;
13         System.out.println(basicDataSource.getMaxTotal());
14
15     }

C3P0数据库连接池

方式一:

这里我们需要加入两个JAR包:c3p0-0.9.5.2.jar和mchange-commons-java-0.2.11.jar

我们下载的c3p0JAR包中的doc文件夹中的index.html文件,点击该文件->Contents->Quickstart,我们可以看到c3p0数据库连接池的创建步骤,如下图所示(我们使用一些JAR包的时候要善于利用好帮助文档):

import com.mchange.v2.c3p0.*;

...

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("dbuser");
cpds.setPassword("dbpassword");

于是我们的代码就可以这样写了:

1     @Test
2     public void testC3P0() throws Exception{
3         ComboPooledDataSource cpds = new ComboPooledDataSource();
4         cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver
5         cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/atguigu" );
6         cpds.setUser("root");
7         cpds.setPassword("123456");
8         System.out.println(cpds.getConnection());
9     }

运行结果:证明创建成功

五月 09, 2016 4:35:56 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
五月 09, 2016 4:35:57 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
五月 09, 2016 4:35:57 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge1d39g158wpld8tx485|1588809, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge1d39g158wpld8tx485|1588809, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/atguigu, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
com.mchange.v2.c3p0.impl.NewProxyConnection@6776ad [wrapping: com.mysql.jdbc.JDBC4Connection@108b2d7]

方式二:使用配置文件的形式

具体的步骤:

     * 1.创建c3p0-config.xml文件,参考帮助文档中
     *   Appendix B: Configuation Files, etc.的内容
     * 2.创建ComboPooledDataSource实例:
     *   DataSource dataSource =
                new ComboPooledDataSource("helloc3p0");
     *3.从DataSource实例中获取数据库连接

其中c3p0-config.xml中的内容我们进行更改成下面的形式:每一行代表什么我都给出了详细的解释

<c3p0-config>

  <named-config name="helloc3p0">
  <!-- 指定数据源的基本属性 -->
    <property name="user">root</property>
    <property name="password">123456</property>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/atguigu</property>
    <!-- 若数据库中连接数不足时,一次向数据库服务器申请多少个连接    -->
    <property name="acquireIncrement">5</property>
    <!-- 初始化数据库连接时连接的数量 -->
    <property name="initialPoolSize">10</property>
    <!-- 数据库连接池中最小的数据库连接数 -->
    <property name="minPoolSize">5</property>
     <!-- 数据库连接池中最大的数据库连接数 -->
    <property name="maxPoolSize">10</property>

    <!-- 数据库连接池可以维护的Statement的个数 -->
    <property name="maxStatements">10</property>
    <!-- 每个连接同时可以使用的Statement对象的个数 -->
    <property name="maxStatementsPerConnection">5</property>

  </named-config>
</c3p0-config>

我们可以看到named-config name="helloc3p0",我们要创建的数据库连接池的名称是helloc3p0;

第二种方式的具体代码实现:

1     @Test
2     public void testC3P0withConfigFile() throws Exception{
3         DataSource dataSource =
4                 new ComboPooledDataSource("helloc3p0");
5         System.out.println(dataSource.getConnection());
6         ComboPooledDataSource comboPooledDataSource=
7                 (ComboPooledDataSource) dataSource;
8         System.out.println(comboPooledDataSource.getMaxStatements());
9     }

测试一些,运行结果:

1 五月 09, 2016 4:42:15 下午 com.mchange.v2.log.MLog
2 信息: MLog clients using java 1.4+ standard logging.
3 五月 09, 2016 4:42:15 下午 com.mchange.v2.c3p0.C3P0Registry
4 信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
5 五月 09, 2016 4:42:15 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
6 信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 5, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> helloc3p0, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge1d39g1594tqaufcxlm|1588809, idleConnectionTestPeriod -> 0, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://localhost:3306/atguigu, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 10, maxStatementsPerConnection -> 5, minPoolSize -> 5, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
7 com.mchange.v2.c3p0.impl.NewProxyConnection@1bcffb5 [wrapping: com.mysql.jdbc.JDBC4Connection@c1f859]
8 10

此时我们JDBCtools中的获取连接的函数getConnection就可以改写代码了,不是每一次都创建新的数据库连接,而是从数据库连接池中获取连接,release函数也不是真正的关闭连接了,而是把数据库连接继续放到连接池中。

 1     private static DataSource dataSource=null;
 2     //数据库连接池只被初始化一次
 3     static {
 4         dataSource=new ComboPooledDataSource("helloc3p0");
 5     }
 6     // 获取数据库连接
 7     public static Connection getConnection() throws  Exception{
 8
 9         /*    ClassNotFoundException, SQLException {
10         Properties properties = new Properties();
11         InputStream inputStream = JDBCTest.class.getClassLoader()
12                 .getResourceAsStream("jdbc.properties");
13         properties.load(inputStream);
14         String user = properties.getProperty("user");
15         String password = properties.getProperty("password");
16         String jdbcUrl = properties.getProperty("jdbcUrl");
17         String driverClass = properties.getProperty("driver");
18         Class.forName(driverClass);
19         Connection connection = DriverManager.getConnection(jdbcUrl, user,
20                 password);*/
21
22         return dataSource.getConnection();
23     }

数据库连接池一般只有一个,所以我们用static修饰,并使用静态代码块的形式初始化数据库连接池,getConnection中的被注释代码使我们原来的获取连接的方式,可以看到代码简洁了不少!

最后附上两部分用到的JAR包:链接:http://pan.baidu.com/s/1eSjUDn8 密码:49zw

【转】JDBC学习笔记(8)——数据库连接池(dbcp&C3P0)的更多相关文章

  1. JDBC学习笔记(8)——数据库连接池(dbcp&C3P0)

    JDBC数据库连接池的必要性 一.在使用开发基于数据库的web程序时,传统的模式基本是按一下步骤: 1)在主程序(如servlet/beans)中建立数据库连接 2)进行sql操作 3)断开数据库连接 ...

  2. JDBC编程学习笔记之数据库连接池的实现

    在JDBC编程的时候,获取到一个数据库连接资源是很宝贵的,倘若数据库访问量超大,而数据库连接资源又没能得到及时的释放,就会导致系统的崩溃甚至宕机.造成的损失将会是巨大的.再看有了数据库连接池的JDBC ...

  3. java之数据库连接池-dbcp&c3p0&dbutils

    介绍 因为数据库连接对象的创建比较消耗性能,所以可以在应用程序启动时就在内存中开辟一片空间(集合)存放多个数据库连接对象,后面需要连接时直接从该空间中取而不用新创建:使用完毕后归还连接(将连接重新放回 ...

  4. java学习笔记—第三方数据库连接池包1(29)

    第一步:导入dbcp包 第二步:通过核心类连接数据 BasicDataSource它是javax.sql.DataSrouce的子类. 一个工具类:BasicDataSourceFactory. 手工 ...

  5. java攻城狮之路--复习JDBC(数据库连接池 : C3P0、DBCP)

    复习数据库连接池 : C3P0.DBCP 1.数据库连接池技术的优点: •资源重用:      由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销.在减少系统消耗的基础上,另一方面也增 ...

  6. JDBC学习笔记二

    JDBC学习笔记二 4.execute()方法执行SQL语句 execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象 ...

  7. [数据库连接池] Java数据库连接池--DBCP浅析.

    前言对于数据库连接池, 想必大家都已经不再陌生, 这里仅仅设计Java中的两个常用数据库连接池: DBCP和C3P0(后续会更新). 一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务 ...

  8. 常用数据库连接池 (DBCP、c3p0、Druid) 配置说明

    1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库 ...

  9. java常用数据库连接池 (DBCP、c3p0、Druid) 配置说明

    1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库 ...

随机推荐

  1. 走进 Redis 的世界

    NoSQL(Not Only SQL) 在现今已经应用非常普遍了,尤其是 Redis 和 MongoDB.我们现在来说说 Redis. 前世 Redis 是一个意大利人 Salvatore Sanfi ...

  2. Pascal's Triangle II leetcode

    Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3,Return [1,3, ...

  3. Source Map入门教程

    部署前端之前,开发者通常会对代码进行打包压缩,这样可以减少代码大小,从而有效提高访问速度.然而,压缩代码的报错信息是很难Debug的,因为它的行号和列号已经失真.这时就需要Source Map来还原真 ...

  4. python 接口自动化测试(一)

    一.测试需求描述 对服务后台一系列SOAP接口功能测试 参数传入:根据接口描述构造不同的参数输入值(Json格式) 二.程序设计 通过Excel配置具体的测试用例数据 保存参数为Json格式,预写入预 ...

  5. linux版powershell安装教程(.net core版)

    powershell 传教士 原创文章 始于2016-12-20,2017-03-15改.文章版本目前博客园为最新版. 允许转载,但必须保留名字和出处,否则追究法律责任 问:powershell二进制 ...

  6. jst通用删除数组中重复的值和删除字符串中重复的字符

    以下内容属于个人原创,转载请注明出处,非常感谢! 删除数组中重复的值或者删除字符串重复的字符,是我们前端开发人员碰到很多这样的场景.还有求职者在被面试时也会碰到这样的问题!比如:问删除字符串重复的字符 ...

  7. 海量数据集利用Minhash寻找相似的集合【推荐优化】

    MinHash 首先它是一种基于 Jaccard Index 相似度的算法,也是一种 LSH 的降维的方法,应用于大数据集的相似度检索.推荐系统.下边按我的理解介绍下MinHash 问题背景 给出N个 ...

  8. IT生涯, 我的常用软件清单

    IT生涯, 我的常用软件清单 SkySeraph Jan. 26th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.skysera ...

  9. python中input()与raw_input()的区别到底是啥?-----marsggbo原创作品为你解答

    首先先给出总结:input () = int(raw_input()) 有图有真相!!! 先看看input的例子: 可见用input键入得到int类型的数据,那如果输入一些非int类型的会怎么样呢? ...

  10. (转)KMP算法实现。超级赞!见过的最容易理解的

    网上有很多讲解KMP算法的博客,我就不浪费时间再写一份了.直接推荐一个当初我入门时看的博客吧:http://www.cnblogs.com/yjiyjige/p/3263858.html这位同学用详细 ...