1. 首先,出现 Broken pipe 的错误不是因连接超时所致,这个错误只有在Linux下多发,就是在高并发的情况下,网络资源不足的情况出现的, 会发送SIGPIPE信号,LINUX下默认程序退出的,具体解决办法目前还未找到合适的,有的说法是在Linux的环境变量中设置: _JAVA_SR_SIGNUM = 12 基本就可以解决,但经测试结果看并未解决。对于该问题持续关注中。
2. 之后,Broken pipe 问题未彻底解决,那么对于DBCP连接池只好对一些作废的连接要进行强制回收,若这里不做强制回收的话,最终也就会导致 pool exhausted 了,所以这一步一定要加上保护。配置如下:
- #### 是否在自动回收超时连接的时候打印连接的超时错误
- dbcp.logAbandoned=true
- #### 是否自动回收超时连接
- dbcp.removeAbandoned=true
- #### 超时时间(以秒数为单位)
- dbcp.removeAbandonedTimeout=150
3. 对于DB的 wait_timeout 空闲连接时间设置,在超过该时间值的连接,DB端会强行关闭,经测试结果,即使DB强行关闭了空闲连接,对于DBCP而言在获取该连接时无法激活该连接,会自动废弃该连接,重新从池中获取空闲连接或是重新创建连接,从源代码上看,这个自动完成的激活逻辑并不需要配置任何参数,是DBCP的默认操作。故对于网上的不少说连接池时间配置与DB不协调会导致 Broken pipe 的说法是错误,至少对于DBCP是不会出现该问题,也许C3P0是这样。
不过对于连接池的优化而言,本来就在池里空闲的连接被DB给强行关闭也不件好事,这里可以组合以下几个配置解决该问题:
java 代码
- # false : 空闲时是否验证, 若不通过断掉连接, 前提是空闲对象回收器开启状态
- dbcp.testWhileIdle = true
- # -1 : 以毫秒表示空闲对象回收器由运行间隔。值为负数时表示不运行空闲对象回收器
- # 若需要回收, 该值最好小于 minEvictableIdleTimeMillis 值
- dbcp.timeBetweenEvictionRunsMillis = 300000
- # 1000*60*30 : 被空闲对象回收器回收前在池中保持空闲状态的最小时间, 毫秒表示
- # 若需要回收, 该值最好小于DB中的 wait_timeout 值
- dbcp.minEvictableIdleTimeMillis = 320000
4. 最后,还有一个就是DBCP的maxWait参数,该参数值不宜配置太大,因为在池消耗满时,该会挂起线程等待一段时间看看是否能获得连接,一般到池耗尽的可能很少,若真要耗尽了一般也是并发太大,若此时再挂线程的话,也就是同时挂起了Server的线程,若到Server线程也挂满了,不光是访问DB的线程无法访问,就连访问普通页面也无法访问了。结果是更糕。
这样,通过以上几个配置,DBCP连接池的连接泄漏应该不会发生了(当然除了程序上的连接泄漏),不过对于并发大时Linux上的BrokenPipe 问题最好能彻底解决。但是对于并发量大时,Tomcat或JBoss的服务线程会挂起的原因还是未最终定位到原因,目前解决了DBCP的影响后,估计问题可能会是出现在 mod_jk 与 Tomcat 的连接上了,最终原因也有可能是 broken pipe 所致。关注与解决中……
2.ibatis使用dbcp连接数据库
一、建立数据表(我用的是oracle 9.2.0.1)
prompt PL/SQL Developer import file
prompt Created on 2007年5月24日 by Administrator
set feedback off
set define off
prompt Dropping T_ACCOUNT...
dro p table T_ACCOUNT cascade constraints; (注意:这里由于ISP限制上传drop,所以加了一个空格)
prompt Creating T_ACCOUNT...
create table T_ACCOUNT
(
ID NUMBER not null,
FIRSTNAME VARCHAR2(2),
LASTNAME VARCHAR2(4),
EMAILADDRESS VARCHAR2(60)
)
;
alter table T_ACCOUNT
add constraint PK_T_ACCOUNT primary key (ID);
prompt Disabling triggers for T_ACCOUNT...
alter table T_ACCOUNT disable all triggers;
prompt Loading T_ACCOUNT...
insert into T_ACCOUNT (ID, FIRSTNAME, LASTNAME, EMAILADDRESS)
values (1, '王', '三旗', 'E_wsq@msn.com');
insert into T_ACCOUNT (ID, FIRSTNAME, LASTNAME, EMAILADDRESS)
values (2, '冷', '宫主', 'E_wsq@msn.com');
commit;
prompt 2 records loaded
prompt Enabling triggers for T_ACCOUNT...
alter table T_ACCOUNT enable all triggers;
set feedback on
set define on
prompt Done.
二、在工程中加入
commons-dbcp-1.2.2.jar
commons-pool-1.3.jar
ibatis-common-2.jar
ibatis-dao-2.jar
ibatis-sqlmap-2.jar
三、编写如下属性文件
jdbc.properties
#连接设置
driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@90.0.12.112:1521:ORCL
username=gzfee
password=1
#<!-- 初始化连接 -->
initialSize=10
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#最大连接数量
maxActive=50
#是否在自动回收超时连接的时候打印连接的超时错误
logAbandoned=true
#是否自动回收超时连接
removeAbandoned=true
#超时时间(以秒数为单位)
removeAbandonedTimeout=180
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=1000
四、将上面建立的属性文件放入classes下
注:如果是用main类测试则应在工程目录的classes下,如果是站点测试则在web-inf的classes目录下
五、写ibatis与DBCP的关系文件
DBCPSqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<properties resource ="jdbc.properties"/>
<transactionManager type ="JDBC">
<dataSource type ="DBCP">
<property name ="JDBC.Driver" value ="${driverClassName}"/>
<property name ="JDBC.ConnectionURL" value ="${url}" />
<property name ="JDBC.Username" value ="${username}" />
<property name ="JDBC.Password" value ="${password}" />
<property name ="Pool.MaximumWait" value ="30000" />
<property name ="Pool.ValidationQuery" value ="select sysdate from dual" />
<property name ="Pool.LogAbandoned" value ="true" />
<property name ="Pool.RemoveAbandonedTimeout" value ="1800000" />
<property name ="Pool.RemoveAbandoned" value ="true" />
</dataSource>
</transactionManager>
<sqlMap resource="com/mydomain/data/Account.xml"/> (注:这里对应表映射)
</sqlMapConfig>
六、写数据表映射文件
Account.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="Account">
<!-- Use type aliases to avoid typing the full classname every time. -->
<typeAlias alias="Account" type="com.mydomain.domain.Account"/>
<!-- Result maps describe the mapping between the columns returned
from a query, and the class properties. A result map isn't
necessary if the columns (or aliases) match to the properties
exactly. -->
<resultMap id="AccountResult" class="Account">
<result property="id" column="id"/>
<result property="firstName" column="firstName"/>
<result property="lastName" column="lastName"/>
<result property="emailAddress" column="emailAddress"/>
</resultMap>
<!-- Select with no parameters using the result map for Account class. -->
<select id="selectAllAccounts" resultMap="AccountResult">
select * from T_ACCOUNT
</select>
<!-- A simpler select example without the result map. Note the
aliases to match the properties of the target result class. -->
<select id="selectAccountById" parameterClass="int" resultClass="Account">
select
id as id,
firstName as firstName,
lastName as lastName,
emailAddress as emailAddress
from T_ACCOUNT
where id = #id#
</select>
<!-- Insert example, using the Account parameter class -->
<insert id="insertAccount" parameterClass="Account">
insert into T_ACCOUNT (
id,
firstName,
lastName,
emailAddress
values (
#id#, #firstName#, #lastName#, #emailAddress#
)
</insert>
<!-- Update example, using the Account parameter class -->
<update id="updateAccount" parameterClass="Account">
update T_ACCOUNT set
firstName = #firstName#,
lastName = #lastName#,
emailAddress = #emailAddress#
where
id = #id#
</update>
<!-- Delete example, using an integer as the parameter class -->
<delete id="deleteAccountById" parameterClass="int">
delet e from T_ACCOUNT where id = #id# (注意:这里由于ISP限制上传delete,所以加了一个空格)
</delete>
</sqlMap>