Hibernate + Spring + Druid 數據庫mysql
由於配置如下
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${datasource.url}" /> <property name="username" value="${datasource.username}" /> <property name="password" value="${datasource.password}" /> <!-- 驅動類 --> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <!-- 默認自動提交狀態。如果不設置,則setAutoCommit 方法將不被調用 --> <property name="defaultAutoCommit" value="true" /> <!-- 屬性類型是字符串,通過別名的方式配置擴展插件,常用的插件有:監控統計用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall --> <!-- <property name="filters" value="stat" /> --> <property name="filters" value="config,stat,log4j" /> <!-- 可以在這個池中同時被分配的有效連接數的最大值 --> <property name="maxActive" value="600" /> <!-- 初始化時建立物理連接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時 --> <property name="initialSize" value="2" /> <!-- 獲取連接時最大等待時間,單位毫秒。配置了maxWait之后,缺省啟用公平鎖,並發效率會有所下降,如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。--> <property name="maxWait" value="40000" /> <!-- 最小連接池數量 --> <property name="minIdle" value="0" /> <!-- 有兩個含義:1) Destroy線程會檢測連接的間隔時間 2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- Destory線程中如果檢測到當前連接的最后活躍時間和當前時間的差值大於 minEvictableIdleTimeMillis,則關閉當前連接 --> <property name="minEvictableIdleTimeMillis" value="8000" /> <!-- 用來檢測連接是否有效的sql,要求是一個查詢語句。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會其作用。 在mysql中通常為select 'x',在oracle中通常為select 1 from dual --> <property name="validationQuery" value="select 1 from dual" /> <!-- 建議配置為true,不影響性能,並且保證安全性。申請連接的時候檢測,如果空閑時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。 --> <property name="testWhileIdle" value="false" /> <!-- 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。--> <property name="testOnBorrow" value="false" /> <!-- 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能 --> <property name="testOnReturn" value="false" /> <!-- 要啟用PSCache,必須配置大於0,當大於0時,poolPreparedStatements自動觸發修改為true。在Druid中,不會存在Oracle下PSCache占用內存過多的問題,可以把這個數值配置大一些,比如說100 --> <property name="maxOpenPreparedStatements" value="200" /> <!-- 對於建立時間超過removeAbandonedTimeout的連接強制關閉 --> <property name="removeAbandoned" value="true" /> <!-- 打開removeAbandoned功能 --> <!-- 180秒,也就是3分鍾 --> <property name="removeAbandonedTimeout" value="1800" /> <!-- 關閉abanded連接時輸出錯誤日志 --> <property name="logAbandoned" value="true" /> </bean>
從配置可以看到,我的連接數max = 600, 但是程序跑到不到一會就報連接數不夠, 獲取不了連接數就一直卡在那里,重啟tomcat服務器,過一會又是這樣
從數據庫 SHOW PROCESSLIST 發現好多連接數在 sleep , sleep 說明連接數沒有被釋放一直在被占用
分析思路
1 分析代碼中可能有沒有 未關閉的數據庫連接
2 查看配置文件時候正確
代碼中
如果代碼中出現 Session session = getSession(); 最后最好加上 session.close(); 這樣就手動釋放了這個連接,也可以換一種獲取連接的方式
public class UniversalDao extends HibernateDaoSupport { public void delete(Class clazz, Serializable id) { getHibernateTemplate().delete(get(clazz, id)); } public List findByCriteria(DetachedCriteria criteria) { return getHibernateTemplate().findByCriteria(criteria); } }
這樣 getHibernateTemplate() 獲取數據連接
配置文件中
<!-- 對於建立時間超過removeAbandonedTimeout的連接強制關閉 --> <property name="removeAbandoned" value="true" /> <!-- 打開removeAbandoned功能 --> <!-- 180秒,也就是3分鍾 --> <property name="removeAbandonedTimeout" value="180" /> <!-- 世界設置小 3分鍾sleep 直接強制關閉 --> <!-- 關閉abanded連接時輸出錯誤日志 --> <property name="logAbandoned" value="true" />
關聯hibernate 配置中
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${hibernate.dialect} </prop> <prop key="hibernate.show_sql"> ${hibernate.show_sql} </prop> <prop key="hibernate.jdbc.fetch_size"> ${hibernate.jdbc.fetch_size} </prop> <prop key="hibernate.jdbc.batch_size"> ${hibernate.jdbc.batch_size} </prop> <prop key="hibernate.format_sql"> ${hibernate.format_sql} </prop> <prop key="hibernate.c3p0.max_statements"> ${hibernate.c3p0.max_statements} </prop> <prop key="hibernate.hbm2ddl.auto">none</prop> <prop key="hibernate.connection.release_mode">after_transaction</prop> </props> </property>
屬性 key="hibernate.connection.release_mode" 這一列要填 after_transaction, 如果是auto也會很有可能初戀數據庫連接一直活躍被占用
好了,這幾個地方注意下,基本上是可以解決問題的