一次高并发问题记录
场景复述:
-
目前做了一个Excel导入的功能:
-
先读取整个Excel,遍历读取到的List将数据库中已存在等无效数据的剔除
-
批量插入数据库
-
-
问题复现:
- 连续两次导入同一份文件
- 结果:
- 数据库中存在两份相同的数据
- 原因分析:
上次的导入还没执行完毕,这次又导入。每次查询数据库都显示库位不存在,所以插入了两遍。
目前现场只要等上次导入结果出来后,再导入就不会出现问题。
- 解决方案:
- 最简单的方案是加锁,串行导入 – 但是本来导入速度就慢 加锁后性能就更是个问题,好在导入使用频率不高,并且这个解决方案最快速
- 在bathInsert的时候数据库使用
INSERT IGNORE INTO
(INSERT IGNORE INTO表示,如果中已经存在相同的记录,则忽略当前新数据) 但是这个东西需要一个唯一索引!也就是说我们要给线上数据库增加一个code字段的唯一索引!但是线上数据已经是脏数据了(一定存在编码code重复的数据,因为删除我采用的是软删除),所以执行新增唯一索引为时已晚!!!
关于唯一索引问题:
想起阿里巴巴Java开发手册里一些内容:
索引规约:
-
【强制】业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。 说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但 高查找速度是明 显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必 然有脏数据产生。
墨菲定律:
一、任何事都没有表面看起来那么简单;
二、所有的事都会比你预计的时间长;
三、会出错的事总会出错;
四、如果你担心某种情况发生,那么它就更有可能发生。有唯一特性还不建立唯一索引真是浪费数据库的能力,数据库的唯一校验比代码准多了)
-
【参考】创建索引时避免有如下极端误解:
- 误认为一个查询就需要建一个索引。(只要用到的索引能把数据查询范围缩小很多就可以了,比如说原来1000万数据,其中光item_id字段就能把范围降到100以内,那么查询条件里那些begin_time字段就不用一起建立组合索引了
- 误认为索引会消耗空间、严重拖慢更新和新增速度。(难道不会拖慢吗?)
- 误认为唯一索引一律需要在应用层通过“先查后插”方式解决。