ivaneeo's blog

自由的力量,自由的生活。

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

ibatis dbcp连接数据库问题(上)

 (2007-12-20 22:43:33)
标签: 

it/科技

分类: javaEE
我是懒人,就不自己写了,就直接引用我找到的两篇博文:
最近网站会出现一个现象是,在并发量大的时候,Tomcat或JBoss的服务线程会线程挂起,同时服务器容易出现数据连接的 java.net.SocketException: Broken pipe  的错误。刚才开始咋一看感觉像是DB端处理不来或是DB端的连接时间到了wait_timeout 的时间强行断开。出于这两个目的,网收集了一些资料后,有的说法是在DB的 wait_timeout 时间后断开的一些连接在连接池中处于空闲状态,当应用层获取该连接后进行的DB操作就会发生上面这个错误。
     但在我查看了DBCP连接池代码和做了些测试后,发生这种说法并非正确。
     1. 首先,出现 Broken pipe 的错误不是因连接超时所致,这个错误只有在Linux下多发,就是在高并发的情况下,网络资源不足的情况出现的, 会发送SIGPIPE信号,LINUX下默认程序退出的,具体解决办法目前还未找到合适的,有的说法是在Linux的环境变量中设置: _JAVA_SR_SIGNUM = 12 基本就可以解决,但经测试结果看并未解决。对于该问题持续关注中。
     2. 之后,Broken pipe 问题未彻底解决,那么对于DBCP连接池只好对一些作废的连接要进行强制回收,若这里不做强制回收的话,最终也就会导致 pool exhausted 了,所以这一步一定要加上保护。配置如下:
  1. #### 是否在自动回收超时连接的时候打印连接的超时错误   
  2. dbcp.logAbandoned=true  
  3. #### 是否自动回收超时连接   
  4. dbcp.removeAbandoned=true  
  5. #### 超时时间(以秒数为单位)   
  6. dbcp.removeAbandonedTimeout=150  

     3. 对于DB的 wait_timeout 空闲连接时间设置,在超过该时间值的连接,DB端会强行关闭,经测试结果,即使DB强行关闭了空闲连接,对于DBCP而言在获取该连接时无法激活该连接,会自动废弃该连接,重新从池中获取空闲连接或是重新创建连接,从源代码上看,这个自动完成的激活逻辑并不需要配置任何参数,是DBCP的默认操作。故对于网上的不少说连接池时间配置与DB不协调会导致 Broken pipe 的说法是错误,至少对于DBCP是不会出现该问题,也许C3P0是这样。
      不过对于连接池的优化而言,本来就在池里空闲的连接被DB给强行关闭也不件好事,这里可以组合以下几个配置解决该问题:

java 代码
  1. false 空闲时是否验证, 若不通过断掉连接, 前提是空闲对象回收器开启状态   
  2. dbcp.testWhileIdle true  
  3. -1 以毫秒表示空闲对象回收器由运行间隔。值为负数时表示不运行空闲对象回收器   
  4. 若需要回收, 该值最好小于 minEvictableIdleTimeMillis 值   
  5. dbcp.timeBetweenEvictionRunsMillis 300000 
  6. 1000*60*30 被空闲对象回收器回收前在池中保持空闲状态的最小时间, 毫秒表示   
  7. 若需要回收, 该值最好小于DB中的 wait_timeout   
  8. 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>

 

posted on 2011-04-22 13:45 ivaneeo 阅读(1032) 评论(0)  编辑  收藏 所属分类: java魔力

只有注册用户登录后才能发表评论。


网站导航: