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>