最近在做的一個項目需要使用多線程Java應(yīng)用程序與服務(wù)器上的Oracle數(shù)據(jù)庫頻繁進行數(shù)據(jù)交互。開發(fā)完成后嗜傅,我們重新進行了多次安全性檢查金句,具體項目如下:
1、在多線程調(diào)用吕嘀,特別是循環(huán)調(diào)用時违寞,實例化的preparedStatement變量必須在使用后或下一次實例化之前進行關(guān)閉操作,必要時還需要將該變量置空偶房,幫助JVM進行垃圾回收趁曼。
PreparedStatement ps = null;
if (ps != null) {
ps.close();
ps = null;
}
如果不及時對使用過的資源進行關(guān)閉和回收,ps與數(shù)據(jù)庫建立的連接不會自動得到釋放棕洋,導(dǎo)致程序報錯:ORA-01000: maximum open cursors exceeded 或者干脆不報錯彰阴,返回空的查詢結(jié)果等等。
2拍冠、與及時關(guān)閉ps的原理類似尿这,線程中對數(shù)據(jù)庫進行的UPDATE簇抵,INSERT和DELETE等操作必須及時commit。由于Oracle數(shù)據(jù)庫在commit時會將同一張表的非查詢訪問串行化射众,不及時commit可能導(dǎo)致鎖表等嚴(yán)重后果碟摆。這里出現(xiàn)的鎖表在日志上顯示的十分尷尬,一般為徹底卡死叨橱,不報錯典蜕,不執(zhí)行finally代碼段,也看不到任何后續(xù)輸出罗洗。
myConnection.commit();
然而愉舔,過分迅速的commit往往也不是好事,當(dāng)一個線程中的其他程序出錯時伙菜,數(shù)據(jù)庫操作的回滾顯得十分必要轩缤。它在一定程度上避免了錯誤的數(shù)據(jù)庫交互,增加了代碼邏輯的魯棒性贩绕。一般來說火的,可以使用下列操作:
首先,獲取一個數(shù)據(jù)庫連接淑倾,保存該連接之前的isAutoCommit屬性馏鹤,將當(dāng)前的autoCommit屬性設(shè)置為false。當(dāng)確定線程中所有代碼依預(yù)定邏輯正確執(zhí)行時娇哆,commit該連接湃累,并將其isAutoCommit屬性恢復(fù)到之前的狀態(tài)。
3碍讨、當(dāng)多個線程同時對多張表進行操作時治力,可能出現(xiàn)互鎖的問題。例如:
假設(shè)線程1和線程2都在本線程結(jié)束時才進行commit操作垄开,當(dāng)線程1在表B中插入數(shù)據(jù)時琴许,表B暫時被鎖税肪,不允許其他線程進行非查詢操作溉躲。同一時間,線程2在表C中插入數(shù)據(jù)益兄,表C暫時被鎖锻梳,不允許其他線程進行非查詢操作。接下來净捅,如果線程1想要更新表C中的數(shù)據(jù)疑枯,就會進入排隊等待的狀態(tài),同樣蛔六,線程2也無法對表B進行數(shù)據(jù)更新荆永,導(dǎo)致兩個線程互鎖废亭。
該問題的解決方案之一是將兩個線程對各張表操作的順序整理一致,例如:
這樣就可以避免發(fā)生上述互鎖情況了具钥。