oracle jdbc 邪惡數(shù)字"65536" ---批量插入10萬條記錄引發(fā)的“血案”
1. 故事背景:
mysql數(shù)據(jù)遷移到oracle,其中有個表名叫“bil_vip”,有10萬條記錄,遷移后檢查發(fā)現(xiàn)oracle數(shù)據(jù)庫只插入34464條記錄,程序執(zhí)行過程沒有發(fā)現(xiàn)任何錯誤。修改數(shù)據(jù)庫連接代碼向mysql插入10萬條記錄,結(jié)果都插入OK。
批量插入使用spring jdbctemplate.batchUpdate(sql, new BatchPreparedStatementSetter());方法,該方法的核心是PreparedStatement的executeBatch方法。
2. 繼續(xù)實(shí)驗(yàn):
新建一個Test表,只有一個name字段做實(shí)驗(yàn)。
拋棄jdbctemplate,直接使用PreparedStatement做實(shí)驗(yàn),結(jié)果和jdbcTemplate是一樣的,實(shí)驗(yàn)證明總是會丟失65536條記錄。
oracle 驅(qū)動的問題?換了最新driver,還是不行。繼續(xù)探索....
3. 希望之光:
早上發(fā)了個消息向大家征求思路,繼中說了一句分批處理,點(diǎn)亮了我的思路。按照繼中提供思路,每1萬條記錄一批,分多批發(fā)送給Oracle。
結(jié)果喜出望外,10萬條記錄全部插入成功。但是"65536"這個數(shù)字是什么意思呢......
在網(wǎng)上搜索文章發(fā)現(xiàn),這個65536是一個bug。當(dāng)PreparedStatement批量處理正好65536個記錄時候,程序會掛死。我試了一下真的掛死了,太嚇人了,這坑夠深的。
4. 解決方案:
spring jdbctemplate還是很好用的,而且業(yè)務(wù)已經(jīng)被我封裝了,如果使用PreparedStatement意味著多了一個處理分支,以后維護(hù)會很麻煩。
我新建一個MyJdbcTemplate類,繼承 jdbctemplate類,并覆蓋了batchUpdate方法。這下舒服了,系統(tǒng)又恢復(fù)了整潔。
5. ★ 結(jié)論和收獲:
ü 有事多思考,多請教身邊同事。
ü 堅(jiān)持Open-close原則(Open for extension, Closed for modification)會系統(tǒng)更好的擴(kuò)展,非常容易維護(hù),關(guān)鍵是要堅(jiān)持這個原則,如果我因?yàn)橐粋€特殊分支使用了PreparedStatement,這樣勢必破壞了這個原則,日后的維護(hù)必然會很麻煩。
ü 基于oracle數(shù)據(jù)如果使用jdbc批量,一定要分批發(fā)送數(shù)據(jù)oracle,否則正好發(fā)一個65536系統(tǒng)就掛死,大于65536數(shù)據(jù)就丟失,杯具呀......
6. 題目何以為“血案”:
周二打球回家就想這個問題,打開筆記本調(diào)試,不知不覺搞到很晚,影響媳婦睡覺(媳婦早上5:30上班),被痛罵一頓,趕緊上床睡覺,我媳婦氣的不行,手痛砸了一下床板(我們的床撤掉了床墊,只有床架和木板),床一下子塌了,把媳婦嚇壞了,把我腿弄傷了一塊,唉,“血案”呀。
posted on 2012-01-31 20:17 蜂鳥 閱讀(1451) 評論(1) 編輯 收藏 所屬分類: j2ee架構(gòu)