1、前景

事情是这样的 ,项目中有一个定时器,每小时拉取另外一张表的数据做一下统计,统计的结果写写到 统计表中,今天上午领导发现表中有两条一模一样的数据,这样我开始做排查

2、问题排查

首先,我之前开发了一个手动触发的接口,可以进行手动调用,调用一次发现没有什么问题,

然后,修改本地时间,做模拟的 触发,发现也没啥问题,

再然后 ,查看开发环境服务器上的log 日志,这里就体现了 log.info() 的重要性啦

终于 灵机一动,是否是多端同事运行导致 数据重复写入呢?因为我们目前的项目是单机系统,没有做分布式的处理,

然后开始验证,

3、验证猜想

先将项目打一下jar 包,准备再本地同时运行 两个一样的项目 (注意修改端口号)

然后修改本地时间,给定时器触发条件

同时运行 jar 和 idea 项目

GSuCL9.png

到时间 查看数据库

GSunQe.png

果不其然,出现重复,

4、问题解决

ok ,问题排查到了,接下来就开始解决问题,

4.1解决方案1

第一想到的解决方案就是锁,mysql 锁,也是最简单的一个方式,那么这个锁如何加呢?

可以通过事务的方式加mysql 锁,之前在网上看到一张图就可以完美理解 事务与MySQL锁的对应关系

GSM6r4.png

ok ,加事务之后,我们看看效果,

同样的当时验证,同时运行两个项目

GSQuyF.png

可以看到,log 已经体现 事务的生效,

再看看数据库的数据

GSQgl8.png

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)

这样就可以解决报错的问题,完美

*方案二来源csdn 直立行走的大瓶子博文