关于数据库连接池的方方面面

  要说数据库连接池,我们先来谈谈对象池的概念

  所谓对象池,就是把频繁使用的对象缓存起来,可以重复使用。首先:一个对象的生存周期包括:对象的创建、对象的使用、对象的销毁。

1、对于对象的创建,我们知道,Java对象是通过构造函数来创建的,在这一过程中,该构造函数链中的所有构造函数也都会被自动调用。另外,默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和double变量设置成0.0,逻辑值设置成false。所以用new关键字来新建一个对象的时间开销是很大的;

2、对于对象的销毁,Java语言的一个优势,就是Java程序员勿需再像C/C++程序员那样,显式地释放对象,而由称为垃圾收集器(Garbage Collector)的自动内存管理系统,定时或在内存凸现出不足时,自动回收垃圾对象所占的内存。凡事有利总也有弊,这虽然为Java程序设计者提供了极大的方便,但同时它也带来了较大的性能开销。这种开销包括两方面,首先是对象管理开销,GC为了能够正确释放对象,它必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等。其次,在GC开始回收“垃圾”对象时,系统会暂停应用程序的执行,而独自占用CPU。
3、基于以上的考虑,如果是一个需要频繁被使用的对象(并且该对象在重复使用前,无需任何处理,属于没有状态的对象如String),将极大影响程序的性能,所以引入了对象池技术,核心原理是:缓存和共享即对于那些被频繁使用的对象,在使用完后,不立即将它们释放,而是将它们缓存起来,以供后续的应用程序重复使用,从而减少创建对象和释放对象的次数,进而改善应用程序的性能。事实上,由于对象池技术将对象限制在一定的数量,也有效地减少了应用程序内存上的开销。
4、 采用对象池化的本意,是要通过减少对象生成的次数,减少花在对象初始化上面的开销,从而提高整体的性能。然而池化处理本身也要付出代价,因此,并非任何情况下都适合采用对象池化。基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合进行对象池化。如果进行池化所能带来的性能提高并不重要的话,还是不采用对象池化技术,以保持代码的简明,而使用更好的硬件和更棒的虚拟机来提高性能为佳。

说了一堆的对象池技术,其实数据连接池在一定程度上采用的技术原理类似对象池技术,我们都知道数据库连接是非常宝贵的资源,而对于数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,采用数据库连接池,它在初始化时创建minConn的数据库连接,允许应用程序复用创建的连接,当连接池有可用连接时,就可以直接从连接池获得而不用频繁向数据库获取连接,大大减轻了数据库的负载。

数据库连接池配置:

1、最小连接数(minConn):连接池初始化时创建的连接数,过大启动将变慢,但是启动后响应更快;假如过小启动加快,但是最初使用的用户将因为连接池中没有足够的连接不可避免的延缓了执行速度。因此应该在开发的过程中设定较小minConn,而在实际应用的中设定较大minConn;
2、最大连接数(maxConn)是连接池能申请的最大连接数,可以通过反复试验来确定此饱和点。为此在连接池类ConnectionPool中加入两个方法getActiveSize()和getOpenSize(),ActiveSize 表示某一时间有多少连接正被使用,OpenSize表示连接池中有多少连接被打开,反映了连接池使用的峰值。将这两个值在日志信息中反应出来, minConn的值应该小于平均ActiveSize,而maxConn的值应该在activeSize和OpenSize之间

3、 如果最小连接数与最大连接数相差太大,那么最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是空闲超时后被释放。

 

2、使用第三方开源数据库连接池:

l 现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供DataSource 的实现,即连接池的实现, 一些开源组织提供了数据源的独立实现:
  DBCP 数据库连接池
l
实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接
以上的连接池在使用时,
相同点:
  1、均需要编写自己相应的配置文件
  2、调用相应的工厂类获得连接池
  3、通过连接池获得连接
  4、进行自己所要的操作
5、不同点
  DBCP的配置文件,例:类目录下的dbcp.properties文件
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/fday16
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED
  C3P0的配置文件,例:类src下的c3p0-config.xml文件
<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>
 <default-config>
  <property name="driverClass">com.mysql.jdbc.Driver</property>
  <property name="jdbcUrl">jdbc:mysql://localhost:3306/fday16</property>
  <property name="user">root</property>
  <property name="password">root</property>  
  <property name="acquireIncrement">5</property>
  <property name="initialPoolSize">10</property>
  <property name="minPoolSize">5</property>
  <property name="maxPoolSize">20</property>
 </default-config>
</c3p0-config>
  tomcat内置的datasource
配置文件编写方法 主要是配置context元素(一个context元素代表一个web应用),而关于context的元素方法,可通过tomcat主页—TomcatConfiguration—Configuration—Context里面查看context的5种配置方法,我现在是采用在META-INF目录下创建context.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
 <Context>
  <Resource name="jdbc/EmployeeDB"
            auth="Container"
            type="javax.sql.DataSource"
            username="root"
            password="root"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/fday16"
            maxActive="8"
            maxIdle="4"/>
</Context>
 
datasource的创建:
DBCP:
  in=JdbcUtils_dbcp.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
   prop=new Properties();
   prop.load(in);
   ds=BasicDataSourceFactory.createDataSource(prop);
C3P0:
  ds=new ComboPooledDataSource();
在程序运行时,会自动搜索名称为c3p0-config.xml的文件,不需要人工指定,所以配置文件名称确定,不可随便更改
Tomcat内置的数据库连接池
  //找到tomcat中的JNDI容器
  Context envCtx=(Context) initCtx.lookup("java:comp/env");
  //从JNDI容器找到名称为jdbc/EmployeeDB的对象
  ds=(DataSource) envCtx.lookup("jdbc/EmployeeDB");
获取连接:
ds.getConnection();
  Context initCtx = new InitialContext(); //初始化JNDI

在传统的两层结构中,客户端程序在启动时打开数据库连接,在退出程序时关闭数据库连接。这样,在整个程序运行中,每个客户端始终占用一个数据库连接,即使在大量没有数据库操作的空闲时间,如用户输入数据时,从而造成数据库连接的使用效率低下。

在三层结构模式中,数据库连接通过中间层的连接池管理。

连接池的管理策略:

我们采用的方法是一个很有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面应用的非常广泛,把该方法运用到对于连接的分配释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现方法是:

  当客户请求数据库连接时,首先查看连接池中是否有空闲连接(指当前没有分配出去的连接)。假如存在空闲连接,则把连接分配给客户并作相应处理(即标记该连接为正在使用,引用计数加1)。假如没有空闲连接,则查看当前所开的连接数是不是已经达到maxConn(最大连接数),假如没达到就重新创建一个连接给请求的客户;假如达到就按设定的maxWaitTime(最大等待时间)进行等待,假如等待maxWaitTime后仍没有空闲连接,就抛出无空闲连接的异常给用户。

  当客户释放数据库连接时,先判定该连接的引用次数是否超过了规定值,假如超过就删除该连接,并判定当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池布满;假如没超过就将该连接标记为开放状态,可供再次复用。可以看出正是这套策略保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。

 

上面都是关于连接池的一些概念性的东西,而对连接池的创建,下面将具体举例说明:

1、编写自己的数据库连接池:

l 编写连接池需实现java.sql.DataSource接口DataSource接口中定义了两个重载的getConnection方法:
Connection getConnection()
Connection getConnection(String username, String password)
l 实现DataSource接口,并实现连接池功能的步骤:
DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList,而不要把conn还给数据库。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值