問題描述:
在 Tomcat 上運行 DBCP 時,在閒置一段時間都沒有資料庫連線的動作時,會不定時的出現「No operation allowed after connection closed」的錯誤訊息。
解決方式:
方法一:
在 url 屬性值的最後要加上 autoReconnect = true,不過此方法僅適用於連線時間超過八小時者。
方法二:
在 Tomcat 的 context.xml 中設定 OBCP 的 Resource Tag 上加上「validationQuery」這個屬性值。
範例如下:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/mysql" auth="Container"
type="javax.sql.DataSource"
maxActive="50" maxIdle="30" maxWait="10000"
username="root" password="12345"
driverClassName="com.mysql.jdbc.Driver"
validationQuery="可以執行的 SQL 指令 (例:SELECT SYSDATE FROM DUAL)"
url="jdbc:mysql://127.0.0.1:3306/student?autoReconnect=true"/>
</Context>
大笨鳥 發表在 痞客邦 留言(0) 人氣(291)
這個問題其實一開始是在 Spring 上引發的,所以也可以列入 Spring 的類別中。
出於實驗性質,將工作上兩個專案合併,這兩個專案都以 Spring 為架構基礎,合併時將其中一個專案先包成 jar,由另一個專案所引用,然後修改此專案的 Spring 主配置檔,用 import tag 來引入包在 jar 檔內的其他 Spring 配置檔。因為 jar 檔內的 Spring 配置檔不少但檔名相同,所以使用了萬用字元的宣告方式,如:
<import resource="classpath:/**/services.xml"/>
原本以為這樣一切沒問題,但在啟動完 Tomcat 後卻發現包在 jar 檔內的 Spring 配置檔全都沒被讀入。找了不少網路的文章都沒有解決方法,而 Spring 官方文件上更是說萬用字元可以用在 classpath 與 jar 檔上 (官方文件 4.7.2.1 節)。不得已之下只能去追 Spring 的 Source,一直追到最後發現 Spring 是用 ClassLoader 的 getSource() 去載入萬用字元 * 之前的路徑。
於是我自己寫了一個測試程式直接用 ClassLoader 的 getSource() 去載入位於 jar 檔內的 path,結果發現回傳真的是 null。看來問題並不在 Spring 身上,於是改變找尋問題的關鍵字,終於讓我找到這篇前人問過的問題「getResource(path) fails in jar」,請看第四格 Tom Blough 的回文,裏面提到說這個問題是因為 path 並不存在於 jar 檔中 (because the path itself did not exist in the jar)。同一格回文裏也有提到如何用 eclipse 包出一個含有 path 的 jar 檔,簡述如下:
1. 專案上按右鍵跳出選單,選「Export」-->「Export」,會跳出小視窗
2. 在跳出的小視窗上選「Java」-->「JAR file」,然後按下「Next」鈕,進入包 jar 的視窗。
3. 在包 jar 的視窗裏勾選完要包入 jar 的檔案與 jar 檔路徑。
4. 在同一視窗裏,勾選未於下方 Options 項次裏的「Add directory entries」。
5. 最後按「Finish」鈕完成。
在勾選了 Add directory entries 後重包了 jar 檔,再用 ClassLoader 的 getResource() 去載入位於 jar 檔內的 path,果然回傳不再是 null 了。接著趕緊將新包的 jar 檔放入專案內去執行,但結果還是一樣,位於 jar 檔內的 Spring 配置檔仍是無法讀入,於是再去看了一次官方文件,裏面的 4.7.2.3 節中有提到如果要引入的 Spring 配置檔如果是位於 jar 檔之類非當前的目錄下時,最好要給一個根目錄來識別。
會這樣主要是因為 Java ClassLoader.getResource() 方法若是給一個空字串,則它會當成要載入的 path 是當前目錄而不是 jar 檔,於是再修改一下 import 的寫法:
<import resource="classpath:com/e104/paoservice/**/services.xml"/>
重新啟動 Tomcat 後,果然位於 jar 檔內的 Spring 配置檔都能正確讀入了!
大笨鳥 發表在 痞客邦 留言(0) 人氣(1,449)
今天程式發生了一個罕見的例外:java.util.ConcurrentModificationException
程式的大致內容如下:
for (TreeWindowModel child : childs) {
// 判斷子點是否為葉節點
if (child != null && child.getChilds().size() == 0) {
// 如果是葉節點且無權限者,移除
if (!child.hasAuth) {
childs.remove(child);
}
} else {
child.clearNoAuthLeaf();
}
}
程式的錯誤指向 for (TreeWindowModel child : childs) 這一行,一時之間還真不知道發生什麼錯誤,後來 Eric (感謝 Eric啦!)在 http://www.blogger.com/post-create.g?blogID=4690814976841013329 找到這篇文章,內容是說
『在 Map 或者 Collection 的時候,不要用它們的 API 直接修改集合的內容,如果要修改可以用 Iterator的 remove() 方法』
因此將上述的程式改成:
for (Iterator
it = childs.iterator(); it.hasNext();){
TreeWindowModel child = it.next();
if (child != null && child.getChilds().size() == 0) {
// 如果是葉節點且無權限者,移除
if (!child.hasAuth) {
it.remove();
}
} else {
child.clearNoAuthLeaf();
}
}
這樣程式就不再丟出 java.util.ConcurrentModificationException
大笨鳥 發表在 痞客邦 留言(0) 人氣(124)
之前在寫 java 時一直有個困擾,那就是在宣告 List 或 Map 類別時,不知該如何順便將其初始化,
所以往往要先宣告後再將要放入 List 或 Map 的物件一個一個的放入。
不過今天在追 Struts 2 的原始碼時,發現了一個寫法,可以在宣告的同時順便初始化。寫法如下:
大笨鳥 發表在 痞客邦 留言(0) 人氣(2,818)