帆軟報表FineReport中資料連線的JDBC連線池屬性問題
連線池原理
在帆軟報表FineReport中,連線池主要由三部分組成:連線池的建立、連線池中連線使用的治理、連線池的關閉。下面就著重討論這三部分及連線池的配置問題。
1. 連線池原理
連線池技術的核心思想,是連線複用,通過建立一個數據庫連線池以及一套連線使用、分配、治理策略,使得該連線池中的連線可以得到高效、安全的複用,避免了資料庫連線頻繁建立、關閉的開銷。
另外,由於對JDBC中的原始連線進行了封裝,從而方便了資料庫應用對於連線的使用(特別是對於事務處理),提高了開發效率,也正是因為這個封裝層的存在,隔離了應用的本身的處理邏輯和具體資料庫訪問邏輯,使應用本身的複用成為可能。
1.1 連線池的建立
應用程式中建立的連線池其實是一個靜態的。所謂靜態連線池是指連線池中的連線在系統初始化時就已分配好,且不能隨意關閉連線。Java中提供了很多容器類可以方便的構建連線池,如:Vector、Stack、Servlet、Bean等,通過讀取連線屬性檔案Connections.properties與資料庫例項建立連線。在系統初始化時,根據相應的配置建立連線並放置在連線池中,以便需要使用時能從連線池中獲取,這樣就可以避免連線隨意的建立、關閉造成的開銷。
1.2 連線池的管理
連線池管理策略是連線池機制的核心。當連線池建立後,如何對連線池中的連線進行管理,解決好連線池內連線的分配和釋放,對系統的效能有很大的影響。連線的合理分配、釋放可提高連線的複用,降低了系統建立新連線的開銷,同時也加速了使用者的訪問速度。下面介紹連線池中連線的分配、釋放策略。
連線池的分配、釋放策略對於有效複用連線非常重要,我們採用的方法是一個很有名的設計模式:Reference Counting(引用記數)。該模式在複用資源方面應用的非常廣泛,把該方法運用到對於連線的分配釋放上,為每一個數據庫連線,保留一個引用記數,用來記錄該連線的使用者的個數。
具體實現方法如下:
當客戶請求資料庫連線時,首先檢視連線池中是否有空閒連線(指當前沒有分配出去的連線)。如果存在空閒連線,則把連線分配給客戶並作相應處理(即標記該連線為正在使用,引用計數加1)。如果沒有空閒連線,則檢視當前所開的連線數是不是已經達到maxConn(最大連線數),如果沒達到就重新建立一個連線給請求的客戶;如果達到就按設定的maxWaitTime(最大等待時間)進行等待,如果等待maxWaitTime後仍沒有空閒連線,就丟擲無空閒連線的異常給使用者。
當客戶釋放資料庫連線時,先判斷該連線的引用次數是否超過了規定值,如果超過就刪除該連線,並判斷當前連線池內總的連線數是否小於minConn(最小連線數),若小於就將連線池充滿;如果沒超過就將該連線標記為開放狀態,可供再次複用。可以看出正是這套策略保證了資料庫連線的有效複用,避免頻繁地建立、釋放連線所帶來的系統資源開銷。
1.3 連線池的關閉
當應用程式退出時,應關閉連線池,此時應把在連線池建立時向資料庫申請的連線物件統一歸還給資料庫(即關閉所有資料庫連線),這與連線池的建立正好是一個相反過程。
連線池分配一個連線後如定義一個數據集,點選預覽,執行完對應的sql語句會將所佔用的連線歸還連線池。
2. 連線池的配置
資料庫連線池中到底要放置多少個連線,才能使系統的效能更佳,用minConn和maxConn來限制。
minConn是當應用啟動的時候連線池所建立的連線數,假如過大啟動將變慢,但是啟動後響應更快;假如過小啟動加快,但是最初使用的使用者將因為連線池中沒有足夠的連線不可避免的延緩了執行速度。因此應該在開發的過程中設定較小minConn,而在實際應用的中設定較大minConn。maxConn是連線池中的最大連線數,可以通過反覆試驗來確定此飽和點。
為此在連線池類ConnectionPool中加入兩個方法getActiveSize()和getOpenSize(),ActiveSize 表示某一時間有多少連線正被使用,OpenSize表示連線池中有多少連線被開啟,反映了連線池使用的峰值。將這兩個值在日誌資訊中反應出來, minConn的值應該小於平均ActiveSize,而maxConn的值應該在activeSize和OpenSize之間。
連線池屬性
1. 問題描述
FineReport連線池屬性,使用的是DBCP連線池,下面介紹其設定方法及其屬性中各引數的意義;如果訪問模板時,報連線超時、等待狀態,警告如下:
1. 警告:Cannot get a connection, pool error Timeout waiting for idle object
2. at com.fr.third.org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)
3. at com.fr.third.org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
4. at com.fr.data.pool.MemoryConnection.create(Unknown Source)
5. at com.fr.data.impl.JDBCDatabaseConnection.createConnection(Unknown Source)
則需要把相應連線數調大。
2. 設定方法
點選伺服器>定義資料連線,如下圖所示,點選連線池屬性,彈出連線池屬性編輯框:
這裡的資訊都儲存在%FR_HOME%\WebReport\WEB-INF\resources\datasource.xml檔案下:
<DBCPAttr
initialSize="1"
maxActive="200"
maxIdle="100"
minIdle="2"
maxWait="1000"
validationQuery="q"
testOnBorrow="false"
testOnReturn="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="1000"
numTestsPerEvictionRun="2"
minEvictableIdleTimeMillis="18005000"/>
3. 引數說明
名稱 |
舉例 |
含義 |
初始化連線數 |
initialSize="1" |
初始化執行緒數,開始自動建立一個與資料庫的連線 |
最大活動連線數 |
maxActive="200" |
可以從物件池中取出的物件最大個數,為0表示沒有限制 |
最大空閒連線數 |
maxIdle="100" |
最大等待連線中的數量,設為負數則沒有限制(物件池中物件最大個數) |
最小空閒連線數 |
minIdle="2" |
物件池中物件最小個數 |
最大等待時間(毫秒) |
maxWait="1000" |
最大等待時間,單位為ms,超出時間會丟出錯誤資訊 |
SQL驗證查詢 |
validationQuery="SQL語句" |
驗證連線是否成功,SQL和SELECT指令至少要返回一行 |
獲取連線前檢驗 |
testOnBorrow="false" |
取得物件時是否進行驗證,檢查物件是否有效,預設為false |
歸還連線前檢驗 |
testOnReturn="true" |
返回物件時是否進行驗證,檢查物件是否有效,預設為false |
開啟空閒回收器檢驗 |
testWhileIdle="true" |
空閒時是否進行驗證,檢查物件是否有效,預設為false |
空閒連接回收器休眠時間(毫秒) |
timeBetweenEvictionRunsMillis="1000" |
失效檢查執行緒執行時間間隔,如果小於等於0,不會啟動檢查執行緒 |
空閒連接回收檢查數 |
numTestsPerEvictionRun="2" |
失效檢查執行緒執行次數 |
保持空閒最小時間 |
minEvictableIdleTimeMillis="18005000" |
大於0,進行連線空閒時間判斷,或為0,對空閒的連線不進行驗證 |
最大活動連線數設定超過資料庫中的連線數目,只能按照資料庫中的連線數目為準,如想調至最大,則也要調整資料庫中的連線數目,參考文件連線池滿問題中的解決方案。
連線池滿問題
1. 問題描述
若日誌報ORA-12519 TNS:no appropriate service handler found,是資料庫連線失敗的錯誤,12519錯誤是監聽不能提供服務。
2. 原因
原因是我們定義資料連線後,點選連線時,此時會從用掉一個連線池中的一個連線。而在定義資料集後,點選預覽按鈕,此時連線池就會分配連線,可能會使用之前那個連線(之前的連線已釋放),或分配一個其他的連線或新建一個連線。若此時連線池所有連線都已用完,就會報如下錯誤:
當客戶請求資料庫連線時,首先是檢視連線池中是否有空閒連線(指當前沒有分配出去的連線)。假如存在空閒連線,則把連線分配給使用者,並作相應的處理(即標記該連線為正在使用,引用計數加1)。假如沒有空閒連線,則檢視當前所開的連線數是不是已經達到maxConn(最大連線數),若沒達到就重新建立一個連線給請求的客戶;若達到就按設定的maxWaitTime(最大等待時間)進行等待;若等待maxWaitTime後,仍沒有空閒連線,就丟擲無空閒連線的異常給使用者。
3. 解決方案
若您在FineReport連線池屬性的設定中,已將最大連線數設定得過大,還出現如上的報錯,此時通常就是資料庫程序(processes)達到上限導致的,可增大資料庫中的連線數目來解決此問題。如下在資料庫中修改最大連線數:
Select count(*) from v$process檢視當前的連線數
Select value from v$parameter where name='processes'檢視資料庫允許的最大連線數
Alter system set processes =300 scope = spfile;修改最大連線數
重啟資料庫,再查詢最大連線數,數字改變就表示已修改成功。
說明:當客戶釋放資料庫連線時,先判定該連線的引用次數是否已超過規定值,假如超過就刪除該連線,並判定當前連線池內總的連線數是否小於minConn(最小連線數),若小於就將連線池佈滿;假如沒超過就將該連線標記為開放狀態,可供再次複用。可看出正是這套策略保證了資料庫連線的有效複用,避免頻繁地建立、釋放連線所帶來的系統資源開銷。