记一次程序多端同时运行数据出现重复写入-记一次程序多端同时运行数据出现重复写入
1、前景
事情是这样的 ,项目中有一个定时器,每小时拉取另外一张表的数据做一下统计,统计的结果写写到 统计表中,今天上午领导发现表中有两条一模一样的数据,这样我开始做排查
2、问题排查
首先,我之前开发了一个手动触发的接口,可以进行手动调用,调用一次发现没有什么问题,
然后,修改本地时间,做模拟的 触发,发现也没啥问题,
再然后 ,查看开发环境服务器上的log 日志,这里就体现了 log.info() 的重要性啦
终于 灵机一动,是否是多端同事运行导致 数据重复写入呢?因为我们目前的项目是单机系统,没有做分布式的处理,
然后开始验证,
3、验证猜想
先将项目打一下jar 包,准备再本地同时运行 两个一样的项目 (注意修改端口号)
然后修改本地时间,给定时器触发条件
同时运行 jar 和 idea 项目

到时间 查看数据库

果不其然,出现重复,
4、问题解决
ok ,问题排查到了,接下来就开始解决问题,
4.1解决方案1
第一想到的解决方案就是锁,mysql 锁,也是最简单的一个方式,那么这个锁如何加呢?
可以通过事务的方式加mysql 锁,之前在网上看到一张图就可以完美理解 事务与MySQL锁的对应关系

ok ,加事务之后,我们看看效果,
同样的当时验证,同时运行两个项目

可以看到,log 已经体现 事务的生效,
再看看数据库的数据

ok ,完美
4.2解决方案2
还有一种解决方案比较麻烦,但是也可以解决。
因为我这里时间字段是和另外一个字段 是一种 联合唯一索引的关系,也就是 时间字段可以重复,另外一个字段也可以重复,但是两个字段加一起不能重复,
这样,其实我们可以做联合唯一索引,但是存在的问题就是,如果触发联合唯一索引,后端代码会报错,导致程序中断,
然后就再论坛找到了可以解决问题的方案,就是配合**Insert into…ON DUPLICATE KEY UPDATE…**来使用就不会报错,存在相同的记录,直接忽略
例:
INSERT INTO unit (
id,
unitsubclass,
name,
state
)
VALUES('1111','CPU','CPU','0' ) ON DUPLICATE KEY UPDATE unitsubclass=VALUES(unitsubclass),name =VALUES(name),state =VALUES(state)
这样就可以解决报错的问题,完美