问题
假如我们有一个定时任务,每天凌晨0点,给当天过生日的人,积分加1
@Scheduled(cron = "0 0 0 */1 * * *")
public void updateScore() {
//doSomething...
}
单主机部署下不会有任何问题。
但是如果有多台主机,假设我们有4台,那么这个定时任务就会执行4次,造成积分+4
解决方法
解决方法有很多种:redis + token,redis + 分布式锁,这里我们采用乐观锁
数据库新建一张表:
CREATE TABLE `t_lock` (
`lock_key` varchar(15) NOT NULL COMMENT '定时任务Key',
`utime` bigint(20) NOT NULL COMMENT '用于乐观锁的时间',
UNIQUE KEY `lockUniq` (`lock_key`,`utime`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
一个项目里可能有多个定时任务,lock_key
用来区分定时任务,utime
用于更新操作。
每天凌晨0点,utime传入当天时间(初始值设一个很小的值,保证第一次可以执行),然后执行sql语句:
update
`t_lock`
set
`utime` = #{utime}
where
`lock_key`=#{lock_key} and `utime`<#{utime}
此时4台主机的这个定时任务,只有1台主机执行update成功,并且返回1,其他都返回0,在返回0的时候,直接return
结束
@Scheduled(cron = "0 0 0 */1 * * *")
public void updateScore() {
//tLock对象传入当前时间和key
...
//获取update影响行数
int i = tLockMapper.update(tLock);
if(i == 0) {
return;
}
//doSomething...
}