连接池原理
在帆软报表FineReport中,连接池主要由三部分组成:连接池的建立、连接池中连接使用的治理、连接池的关闭。下面就着重讨论这三部分及连接池的配置问题。
1. 连接池原理
连接池技术的核心思想,是连接复用,通过建立一个数据库连接池以及一套连接使用、分配、治理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
另外,由于对JDBC中的原始连接进行了封装,从而方便了数据库应用对于连接的使用(特别是对于事务处理),提高了开发效率,也正是因为这个封装层的存在,隔离了应用的本身的处理逻辑和具体数据库访问逻辑,使应用本身的复用成为可能。
1.1 连接池的建立
应用程序中建立的连接池其实是一个静态的。所谓静态连接池是指连接池中的连接在系统初始化时就已分配好,且不能随意关闭连接。Java中提供了很多容器类可以方便的构建连接池,如:Vector、Stack、Servlet、Bean等,通过读取连接属性文件Connections.properties与数据库实例建立连接。在系统初始化时,根据相应的配置创建连接并放置在连接池中,以便需要使用时能从连接池中获取,这样就可以避免连接随意的建立、关闭造成的开销。
1.2 连接池的管理
连接池管理策略是连接池机制的核心。当连接池建立后,如何对连接池中的连接进行管理,解决好连接池内连接的分配和释放,对系统的性能有很大的影响。连接的合理分配、释放可提高连接的复用,降低了系统建立新连接的开销,同时也加速了用户的访问速度。下面介绍连接池中连接的分配、释放策略。
连接池的分配、释放策略对于有效复用连接非常重要,我们采用的方法是一个很有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面应用的非常广泛,把该方法运用到对于连接的分配释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。
具体实现方法如下:
当客户请求数据库连接时,首先查看连接池中是否有空闲连接(指当前没有分配出去的连接)。如果存在空闲连接,则把连接分配给客户并作相应处理(即标记该连接为正在使用,引用计数加1)。如果没有空闲连接,则查看当前所开的连接数是不是已经达到maxConn(最大连接数),如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的maxWaitTime(最大等待时间)进行等待,如果等待maxWaitTime后仍没有空闲连接,就抛出无空闲连接的异常给用户。
当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就删除该连接,并判断当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。可以看出正是这套策略保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。
1.3 连接池的关闭
当应用程序退出时,应关闭连接池,此时应把在连接池建立时向数据库申请的连接对象统一归还给数据库(即关闭所有数据库连接),这与连接池的建立正好是一个相反过程。
连接池分配一个连接后如定义一个数据集,点击预览,执行完对应的sql语句会将所占用的连接归还连接池。
2. 连接池的配置
数据库连接池中到底要放置多少个连接,才能使系统的性能更佳,用minConn和maxConn来限制。
minConn是当应用启动的时候连接池所创建的连接数,假如过大启动将变慢,但是启动后响应更快;假如过小启动加快,但是最初使用的用户将因为连接池中没有足够的连接不可避免的延缓了执行速度。因此应该在开发的过程中设定较小minConn,而在实际应用的中设定较大minConn。maxConn是连接池中的最大连接数,可以通过反复试验来确定此饱和点。
为此在连接池类ConnectionPool中加入两个方法getActiveSize()和getOpenSize(),ActiveSize 表示某一时间有多少连接正被使用,OpenSize表示连接池中有多少连接被打开,反映了连接池使用的峰值。将这两个值在日志信息中反应出来, minConn的值应该小于平均ActiveSize,而maxConn的值应该在activeSize和OpenSize之间。
连接池属性
1. 问题描述
FineReport连接池属性,使用的是DBCP连接池,下面介绍其设置方法及其属性中各参数的意义;如果访问模板时,报连接超时、等待状态,警告如下:
1. 警告:Cannot get a connection, pool error Timeout waiting for idle object
2. at com.fr.third.org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)
3. at com.fr.third.org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
4. at com.fr.data.pool.MemoryConnection.create(Unknown Source)
5. at com.fr.data.impl.JDBCDatabaseConnection.createConnection(Unknown Source)
则需要把相应连接数调大。
2. 设置方法
点击服务器>定义数据连接,如下图所示,点击连接池属性,弹出连接池属性编辑框:
这里的信息都保存在%FR_HOME%\WebReport\WEB-INF\resources\datasource.xml文件下:
initialSize="1"
maxActive="200"
maxIdle="100"
minIdle="2"
maxWait="1000"
validationQuery="q"
testOnBorrow="false"
testOnReturn="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="1000"
numTestsPerEvictionRun="2"
minEvictableIdleTimeMillis="18005000"/>
3. 参数说明
名称 |
举例 |
含义 |
初始化连接数 |
initialSize="1" |
初始化线程数,开始自动建立一个与数据库的连接 |
最大活动连接数 |
maxActive="200" |
可以从对象池中取出的对象最大个数,为0表示没有限制 |
最大空闲连接数 |
maxIdle="100" |
最大等待连接中的数量,设为负数则没有限制(对象池中对象最大个数) |
最小空闲连接数 |
minIdle="2" |
对象池中对象最小个数 |
最大等待时间(毫秒) |
maxWait="1000" |
最大等待时间,单位为ms,超出时间会丢出错误信息 |
SQL验证查询 |
validationQuery="SQL语句" |
验证连接是否成功,SQL和SELECT指令至少要返回一行 |
获取连接前检验 |
testOnBorrow="false" |
取得对象时是否进行验证,检查对象是否有效,默认为false |
归还连接前检验 |
testOnReturn="true" |
返回对象时是否进行验证,检查对象是否有效,默认为false |
开启空闲回收器检验 |
testWhileIdle="true" |
空闲时是否进行验证,检查对象是否有效,默认为false |
空闲连接回收器休眠时间(毫秒) |
timeBetweenEvictionRunsMillis="1000" |
失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程 |
空闲连接回收检查数 |
numTestsPerEvictionRun="2" |
失效检查线程运行次数 |
保持空闲最小时间 |
minEvictableIdleTimeMillis="18005000" |
大于0,进行连接空闲时间判断,或为0,对空闲的连接不进行验证 |
最大活动连接数设置超过数据库中的连接数目,只能按照数据库中的连接数目为准,如想调至最大,则也要调整数据库中的连接数目,参考文档连接池满问题中的解决方案。
连接池满问题
1. 问题描述
若日志报ORA-12519 TNS:no appropriate service handler found,是数据库连接失败的错误,12519错误是监听不能提供服务。
2. 原因
原因是我们定义数据连接后,点击连接时,此时会从用掉一个连接池中的一个连接。而在定义数据集后,点击预览按钮,此时连接池就会分配连接,可能会使用之前那个连接(之前的连接已释放),或分配一个其他的连接或新建一个连接。若此时连接池所有连接都已用完,就会报如下错误:
当客户请求数据库连接时,首先是查看连接池中是否有空闲连接(指当前没有分配出去的连接)。假如存在空闲连接,则把连接分配给用户,并作相应的处理(即标记该连接为正在使用,引用计数加1)。假如没有空闲连接,则查看当前所开的连接数是不是已经达到maxConn(最大连接数),若没达到就重新创建一个连接给请求的客户;若达到就按设定的maxWaitTime(最大等待时间)进行等待;若等待maxWaitTime后,仍没有空闲连接,就抛出无空闲连接的异常给用户。
3. 解决方案
若您在FineReport连接池属性的设置中,已将最大连接数设置得过大,还出现如上的报错,此时通常就是数据库进程(processes)达到上限导致的,可增大数据库中的连接数目来解决此问题。如下在数据库中修改最大连接数:
Select count(*) from v$process查看当前的连接数
Select value from v$parameter where name='processes'查看数据库允许的最大连接数
Alter system set processes =300 scope = spfile;修改最大连接数
重启数据库,再查询最大连接数,数字改变就表示已修改成功。
说明:当客户释放数据库连接时,先判定该连接的引用次数是否已超过规定值,假如超过就删除该连接,并判定当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池布满;假如没超过就将该连接标记为开放状态,可供再次复用。可看出正是这套策略保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。