有個空間

          有個標題

          Spring+Hibernate:在applicationContext.xml中配置C3P0參數說明

          背景:
          在項目中遇到下面這個exception
          Exception occurred while logging on

          Hibernate operation: Cannot open connection; uncategorized SQLException 
          for SQL [???];
          SQL state [
          null]; error code [0]; An SQLException was provoked by the following failure:
          com.mchange.v2.resourcepool.ResourcePoolException: Attempted to use a closed or
          broken resource pool; nested exception is java.sql.SQLException: An SQLException was
           provoked by the following failure: com.mchange.v2.resourcepool.ResourcePoolException:
          Attempted to use a closed or broken resource pool

          分析:
          看字面的意思,是連接池出問題。因為對spring的連接池配置不熟,所以就找到下面的文章。
          <引用:http://hi.baidu.com/javazyw/blog/item/4e668fc7e3557ac039db49c3.html>

            1 <?xml version="1.0" encoding="UTF-8"?>
            2 <beans xmlns="http://www.springframework.org/schema/beans"
            3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            4     xmlns:jee="http://www.springframework.org/schema/jee"
            5     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            6             http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
            7     <bean id="dataSource"
            8         class="com.mchange.v2.c3p0.ComboPooledDataSource"
            9         destroy-method="close">
           10         <property name="driverClass">
           11             <value>com.mysql.jdbc.Driver</value>
           12         </property>
           13         <property name="jdbcUrl">
           14             <value>jdbc:mysql://192.168.3.110:3306/DBName?useUnicode=true&amp;characterEncoding=GBK</value>
           15         </property>
           16         <property name="user">
           17             <value>root</value>
           18         </property>
           19         <property name="password">
           20             <value>root</value>
           21         </property>
           22 
           23 <!--連接池中保留的最小連接數。-->
           24         <property name="minPoolSize">
           25             <value>5</value>
           26         </property>
           27 
           28 <!--連接池中保留的最大連接數。Default: 15 -->
           29         <property name="maxPoolSize">
           30             <value>30</value>
           31         </property>
           32 
           33 <!--初始化時獲取的連接數,取值應在minPoolSize與maxPoolSize之間。Default: 3 -->
           34         <property name="initialPoolSize">
           35             <value>10</value>
           36         </property>
           37 
           38 <!--最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->
           39         <property name="maxIdleTime">
           40             <value>60</value>
           41         </property>
           42 
           43 <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->
           44         <property name="acquireIncrement">
           45             <value>5</value>
           46         </property>
           47 
           48 <!--JDBC的標準參數,用以控制數據源內加載的PreparedStatements數量。但由于預緩存的statements
           49 屬于單個connection而不是整個連接池。所以設置這個參數需要考慮到多方面的因素。
           50 如果maxStatements與maxStatementsPerConnection均為0,則緩存被關閉。Default: 0-->
           51         <property name="maxStatements">
           52             <value>0</value>
           53         </property>
           54 
           55 <!--每60秒檢查所有連接池中的空閑連接。Default: 0 -->
           56         <property name="idleConnectionTestPeriod">
           57             <value>60</value>
           58         </property>
           59 
           60 <!--定義在從數據庫獲取新連接失敗后重復嘗試的次數。Default: 30 -->
           61         <property name="acquireRetryAttempts">
           62             <value>30</value>
           63         </property>
           64 
           65 <!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效
           66 保留,并在下次調用getConnection()的時候繼續嘗試獲取連接。如果設為true,那么在嘗試
           67 獲取連接失敗后該數據源將申明已斷開并永久關閉。Default: false-->
           68         <property name="breakAfterAcquireFailure">
           69             <value>true</value>
           70         </property>
           71 
           72 <!--因性能消耗大請只在需要的時候使用它。如果設為true那么在每個connection提交的
           73 時候都將校驗其有效性。建議使用idleConnectionTestPeriod或automaticTestTable
           74 等方法來提升連接測試的性能。Default: false -->
           75         <property name="testConnectionOnCheckout">
           76             <value>false</value>
           77         </property>
           78     </bean>
           79     <!-- Hibernate SessionFactory -->
           80     <bean id="sessionFactory"
           81         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
           82         <property name="dataSource">
           83             <ref local="dataSource" />
           84         </property>
           85         <property name="mappingResources">
           86             <list>
           87                 <value>com/xh/hibernate/vo/User.hbm.xml</value>
           88             </list>
           89         </property>
           90         <property name="hibernateProperties">
           91             <props>
           92                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
           93                 <prop key="hibernate.show_sql">true</prop>
           94                 <prop key="hibernate.generate_statistics">true</prop>
           95                 <prop key="hibernate.connection.release_mode">auto</prop>
           96                 <prop key="hibernate.autoReconnect">true</prop>
           97             </props>
           98         </property>
           99     </bean>
          100 </beans>

          應該是配置的原因。然后有找到這篇個說明
          <引用:http://home.bendixinwen.cn:8080/blog/2010/01/27/1264560312821.html>
          解決這個異常需要修改設置成如下:

          <property name="acquireRetryAttempts">
              
          <value>30</value>
          </property>
          <property name="acquireRetryDelay">
              
          <value>100</value>
          </property>
          <property name="breakAfterAcquireFailure">
              
          <value>false</value>
          </property>
          - acquireRetryAttempts 
          Default: 30 
          Defines how many times c3p0 will try to acquire a new Connection from the database before giving up.
           If this value is less than or equal to zero, c3p0 will keep trying to fetch a Connection indefinitely 

          - acquireRetryDelay 
          Default: 1000 
          Milliseconds, time c3p0 will wait between acquire attempts. 

          - breakAfterAcquireFailure 
          Default: false 
          If true, a pooled DataSource will declare itself broken and be permanently closed
          if a Connection cannot be obtained from the database after making acquireRetryAttempts to acquire one.
          If false, failure to obtain a Connection will cause all Threads waiting for the pool to acquire a Connection
          to throw an Exception, but the DataSource will remain valid, and will attempt to acquire again following a
          call to getConnection().

          再分析:
          為什么會說Attempted to use a closed or broken resource pool,應該是有鏈接沒關閉。因為一直對<session.save>和<geHibernateTemplate().save> 這兩種DAO實現方式不理解。找到下面這篇文章
          <引用:http://jeoff.blog.51cto.com/186264/133434>
          1 自動生成hibernate配置文件的時候,會在dao層用到getSession()方法來操作數據庫記錄,但是他還有個方法getHibernateTemplate(),這兩個方法究竟有什么區別呢?
          2 1.使用getSession()方法你只要繼承sessionFactory,而使用getHibernateTemplate()方法必須繼承 HibernateDaoSupport當然包括sessionFactory,這點區別都不是特別重要的,下面這些區別就很重要了
          3 2.getSession()方法是沒有經過spring包裝的,spring會把最原始的session給你,在使用完之后必須自己調用相應的 close方法,而且也不會對聲明式事務進行相應的管理,一旦沒有及時關閉連接,就會導致數據庫連接池的連接數溢出,getHibernateTemplate()方法是經過spring封裝的,例如添加相應的聲明式事務管理,由spring管理相應的連接。
          4 在實際的使用過程中發現的確getHibernateTemplate()比getSession()方法要好很多,但是有些方法在getHibernateTemplate()并沒有提供,這時我們用HibernateCallback 回調的方法管理數據庫.

          看看黑體標注的那句話,再看看程序代碼會發現確實有很多使用session方式的DAO在最后沒有關閉。root cause應該就是他了。

          總結:

          1. 是用session實現DAO,必須要在最后關閉session,不然會導致連接池鏈接溢出
          2.可以使用 set breakAfterAcquireFailure =false 來規避這個問題。

          尾巴:
          set breakAfterAcquireFailure =false 能不能解決問題 還需要進一步檢驗。下回分解。



          posted on 2010-12-20 11:49 游雯 閱讀(3697) 評論(0)  編輯  收藏 所屬分類: Java技術

          主站蜘蛛池模板: 读书| 聂拉木县| 个旧市| 蒙山县| 嘉鱼县| 十堰市| 德惠市| 万源市| 香港| 景洪市| 正蓝旗| 福州市| 淮南市| 洛阳市| 修水县| 彭泽县| 从化市| 章丘市| 莱阳市| 龙门县| 辉县市| 鄂托克旗| 北安市| 乌兰县| 鄱阳县| 平潭县| 沧源| 普定县| 武宁县| 华亭县| 永丰县| 惠水县| 绥滨县| 武陟县| 洛南县| 新晃| 武川县| 海宁市| 张家港市| 博爱县| 江门市|