有一个线程的问题,就是假如 我有一个文件,然后这个文件有很多条数据,假如有两个字段,一个学号一个钱,(我的需求是,读取文件,把数据插入到表里,先拿文件的学号去查表有这个数据,就把钱进行相加,没有就新增一条数据)现在遇到问题是:我开多线程跑,现在出现了,这个表里有两条数据的概念(不应该是两条,因为读文件有就把钱相加,没有就新增),我感觉是,多个线程拿到了两条一样的学号同时去库里查,都没有查到,把这两条同时新增到了表里。
没看懂?简说下
if (用户不存在) { xxxxx 存储用户到数据库 } else { 更新数据,将钱数进行相加 }
意思是在一条线成操作还没有执行完毕,第二条拥有相同数据的线程已经进入并通过了if的检验,导致数据库存储了两条相同的数据。所以就会导致数据不对,钱并没有加上且数据库出现了多条数据
然后我就百度了一下感觉有一个大佬做出了这个比喻,我觉得很恰当祥和里分享下:
插入Java多线程不安全的场景比喻:苹果饮食竞赛,比如三个人同时吃10个苹果,就会有一个数字问题:当同时执行多个线程的时候,可能会出现线程不安全的问题,当三个人同时获得一个苹果时,他们同时执行了这个操作,就会产生多条数据操作。
解决方案:
然后我就查了许多资料,然后也听朋友说了许多
- 解决的办法,当然加锁是我万不得已的选择才会去选择,因为以我现在的水平,我觉得我对线程的了解仅仅是九牛一毛,根本操控不了
- 还有一个办法就是说首先把所有的文件数据全部导入一张临时表,然后对临时表进行分组 统一进行金钱相加,(说实话这个方法可行,但是时间问题,200多万的数据确实会很慢,所以我也只是考虑并没有使用)
- 最后我想到一个方法就是对查询的学号做约束(也就是做唯一索引,让程序进行插入的时候进行报错,也就是说在sql中如果学号重复,再次进入插入的时候就会报索引唯一 key 什么玩意),然后我在写的代码中进行捕获,一开始怎么捕获还是会抛出错误,后来发现,那个sql主键重复并不是异常,而是error,然后我就记得error也能进行捕获,后来我又找到error的捕获:
error和exception都是可以捕获的,他们两个都是Throwable的子类(这里是重点)
最后我将代码改为:
if (用户不存在) { try { xxxxx 存储用户到数据库 } catch(Throwable e){ 更新数据,将钱数进行相加 } } else { 更新数据,将钱数进行相加 }
问题解决 !!!