一套代码中的定时任务被多个机器运行,数据容易变多或变大的解决办法。分布式锁,代码执行时间
开发中遇到了这样的一个场景,同一套代码在多台机器运行。奇葩的是数据库表都是同一个。由于业务需要写了很多定时任务来批量处理数据。但是在运行过程中发现,当多台机器同时运行同一套代码对同一个数据源操作同一个表的时候会出现跑出来的数据比正式数据要打,或者要多,这个时候就想到了要用锁。
但是单纯的锁只能锁住仅在一台机器运行时并发请求线程的问题(定时任务不仅可以定时运行还可以手动触发运行)。并不能解决问题,这时就要用到分布式锁了。可以用redis的分布式锁。
步骤,代码如下,不多解释
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.3</version>
-- 版本按自己需求
</dependency>
步骤一:注入(前提是有没有redis依赖)
步骤二:代码中运用
@Scheduled(cron = "0 59 23 * * ?")
public void stockAllCityJob(){
String lockey = "stockAllCityJob_stockExchange_lock";
RLock lock = redissonClient.getLock(lockey);
long starttime = System.currentTimeMillis();
try {
if(!lock.tryLock(0,10, TimeUnit.MINUTES)){
log.warn("获取任务锁失败,退出。");
return;
}
log.info("==================================定时任务开始=========================================================");
//业务代码放在这里
log.info("==================================定时任务结束=========================================================");
long endtime = System.currentTimeMillis();
long end = endtime- starttime;
System.out.println("定时任务执行时间:"+end / 1000 / 60 / 60 + "时" + end / 1000 / 60 % 60 + "分" + end / 1000 % 60 + "秒");
} catch (InterruptedException e) {
log.warn("获取任务锁异常,退出。");
return;
}finally {
if(lock.isLocked() && lock.isHeldByCurrentThread()){
lock.unlock();
log.info(Thread.currentThread().getName() + "unlock");
}
}
}
加入分布式锁后不论几台机器几个线程同时运行,最后只能运行最先抢到线程拿到锁的那个任务。
====更新=
解决此类问题还有一个方法,即:代码在多台机器上运行定时任务的时候可以指定定时任务在哪一个服务器ip上才可以运行
这样也可以解决类似的数据问题。
获取当前服务器ip的方法如下
具体代码:
public static void main(String[] args) {
try {
String hostAddress = InetAddress.getLocalHost().getHostAddress();
System.out.println(hostAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
注:此方法仅为个人思路并没有经过项目实际验证过,如有需要仅供参考。