1. 故事背景:
mysql数据迁移到oracle,其中有个表名叫“bil_vip”,有10万条记录,迁移后检查发现oracle数据库只插入34464条记录,程序执行过程没有发现任何错误。修改数据库连接代码向mysql插入10万条记录,结果都插入OK。
批量插入使用spring jdbctemplate.batchUpdate(sql, new BatchPreparedStatementSetter());方法,该方法的核心是PreparedStatement的executeBatch方法。
2. 继续实验:
新建一个Test表,只有一个name字段做实验。
抛弃jdbctemplate,直接使用PreparedStatement做实验,结果和jdbcTemplate是一样的,实验证明总是会丢失65536条记录。
oracle 驱动的问题?换了最新driver,还是不行。继续探索....
3. 希望之光:
早上发了个消息向大家征求思路,继中说了一句分批处理,点亮了我的思路。按照继中提供思路,每1万条记录一批,分多批发送给Oracle。
结果喜出望外,10万条记录全部插入成功。但是"65536"这个数字是什么意思呢......
在网上搜索文章发现,这个65536是一个bug。当PreparedStatement批量处理正好65536个记录时候,程序会挂死。我试了一下真的挂死了,太吓人了,这坑够深的。
4. 解决方案:
spring jdbctemplate还是很好用的,而且业务已经被我封装了,如果使用PreparedStatement意味着多了一个处理分支,以后维护会很麻烦。
我新建一个MyJdbcTemplate类,继承 jdbctemplate类,并覆盖了batchUpdate方法。这下舒服了,系统又恢复了整洁。
5. ★ 结论和收获:
ü 有事多思考,多请教身边同事。
ü 坚持Open-close原则(Open for extension, Closed for modification)会系统更好的扩展,非常容易维护,关键是要坚持这个原则,如果我因为一个特殊分支使用了PreparedStatement,这样势必破坏了这个原则,日后的维护必然会很麻烦。
ü 基于oracle数据如果使用jdbc批量,一定要分批发送数据oracle,否则正好发一个65536系统就挂死,大于65536数据就丢失,杯具呀......
6. 题目何以为“血案”:
周二打球回家就想这个问题,打开笔记本调试,不知不觉搞到很晚,影响媳妇睡觉(媳妇早上5:30上班),被痛骂一顿,赶紧上床睡觉,我媳妇气的不行,手痛砸了一下床板(我们的床撤掉了床垫,只有床架和木板),床一下子塌了,把媳妇吓坏了,把我腿弄伤了一块,唉,“血案”呀。