我們知道現在微服務很流行,為此,許多中小型企業都將自己以前的框架加以改造,其中以SpringCloud為最多,但是SpringCloud如果要加定時任務的話,在單台服務器上很好支持,
但是涉及到集群服務(多台服務的話)就要用到分布式鎖了,最簡單的方案是用Redis,好了廢話不多說,直接上代碼.
1、分布式鎖
/** * 分布式鎖 * * */ @Component public class DistributedLockHandler { private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class); /** * 最大持有鎖的時間(毫秒) */ private final static long LOCK_EXPIRE = 30 * 1000L; /** * 嘗試獲取鎖的時間間隔(毫秒) */ private final static long LOCK_TRY_INTERVAL = 30L; /** * 獲取鎖最大等待時間( 毫秒 ) */ private final static long LOCK_TRY_TIMEOUT = 20 * 1000L; @Resource(name = "customRedisTemplate") private RedisTemplate<String, String> template; /** * 嘗試獲取 分布式鎖 * * @param lockKey * 鎖名 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLock(String lockKey) { return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_TRY_INTERVAL); } /** * 嘗試獲取 分布式鎖(不自動釋放鎖) * * @param lockKey * 鎖名 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLockNotAutoRelease(String lockKey) { return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, -1); } /** * 嘗試獲取 分布式鎖 * * @param lockKey * 鎖名 * @param timeout * 獲取鎖最大等待時間 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLock(String lockKey, long timeout) { return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE); } /** * 嘗試獲取 分布式鎖(不自動釋放鎖) * * @param lockKey * 鎖名 * @param timeout * 獲取鎖最大等待時間 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLockNotAutoRelease(String lockKey, long timeout) { return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, -1); } /** * 嘗試獲取 分布式鎖 * * @param lockKey * 鎖名 * @param timeout * 獲取鎖最大等待時間 * @param tryInterval * 獲取鎖嘗試 時間間隔 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLock(String lockKey, long timeout, long tryInterval) { return getLock(lockKey, timeout, tryInterval, LOCK_EXPIRE); } /** * 嘗試獲取 分布式鎖(不釋放鎖) * * @param lockKey * 鎖名 * @param timeout * 獲取鎖最大等待時間 * @param tryInterval * 獲取鎖嘗試 時間間隔 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLockNotAutoRelease(String lockKey, long timeout, long tryInterval) { return getLock(lockKey, timeout, tryInterval, -1); } /** * 嘗試獲取 分布式鎖 * * @param lockKey * 鎖名 * @param timeout * 獲取鎖最大等待時間 * @param tryInterval * 獲取鎖嘗試 時間間隔 * @param lockExpireTime * 鎖最大持有時間 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean tryLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) { return getLock(lockKey, timeout, tryInterval, lockExpireTime); } /** * 獲取分布式鎖 * * @param lockKey * 鎖名 * @param timeout * 獲取鎖最大等待時間 * @param tryInterval * 獲取鎖嘗試 時間間隔 * @param lockExpireTime * 鎖最大持有時間 * @return true 得到了鎖 ,false 獲取鎖失敗 */ public boolean getLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) { try { if (StringUtils.isEmpty(lockKey)) { return false; } long startTime = System.currentTimeMillis(); do { ValueOperations<String, String> ops = template.opsForValue(); if (ops.setIfAbsent(lockKey, "lockValue")) { if (lockExpireTime > 0) { template.expire(lockKey, lockExpireTime, TimeUnit.MILLISECONDS); } return true; } Thread.sleep(tryInterval); } while (System.currentTimeMillis() - startTime < timeout); } catch (InterruptedException e) { logger.error(e.getMessage()); return false; } return false; } /** * 釋放鎖 * * @param lockKey */ public void unLock(String lockKey) { if (!StringUtils.isEmpty(lockKey)) { template.delete(lockKey); } } }
2、 在定時任務中使用
@Component public class AutoComfirmReceied { private static final Logger logger = LoggerFactory.getLogger(AutoComfirmReceied.class); @Resource OrderService orderService; @Resource OrderItemMapper orderItemMapper; @Autowired DistributedLockHandler distributedLockHandler; @Scheduled(cron = "${cron.autoComfirmReceied}") public void run() { String lockKey = RedisKeyResolver.getLockkey( "AutoComfirmReceied:run" );; if( distributedLockHandler.tryLockNotAutoRelease( lockKey ) ) { try { runTask(); } catch (Exception e) { e.printStackTrace(); }finally { distributedLockHandler.unLock( lockKey ); } }else { if( logger.isDebugEnabled() ) { logger.debug("沒有獲取鎖超時.............."); } } } private void runTask() { logger.info("3分鍾執行一次定時任務" + System.currentTimeMillis()); List<String> orderItemReturnStatus = new ArrayList<>(); orderItemReturnStatus.add(OrderItemReturnStatus.WTH.name()); orderItemReturnStatus.add(OrderItemReturnStatus.YJJ.name()); orderItemReturnStatus.add(OrderItemReturnStatus.YQX.name()); OrderItemExample orderItemExample = new OrderItemExample(); OrderItemExample.Criteria oderc = orderItemExample.createCriteria(); oderc.andIsDelEqualTo(false) .andOrderStatusEqualTo(OrderItemStatus.SENDED.name()) .andReturnStatusIn(orderItemReturnStatus) .andShippingStatusEqualTo(OrderItemShippingStatus.YFH.name()); List<OrderItem> orderItemList = orderItemMapper.selectByExample(orderItemExample); Set<String> set = new HashSet<>(); for (OrderItem orderItem : orderItemList) { Long sendTime10 = AutoConfirmReceivedDateUtil.getAdd10Day(orderItem.getSendDate(), 10); Long currentTime = new Date().getTime(); if(currentTime > sendTime10){ //當前時間大於,發貨后10天的時間,則確認收貨 set.add(orderItem.getLogisticsId() + "," + orderItem.getUserId()); } } if(!set.isEmpty()){ for (String orderItem : set) { String[] item = orderItem.split(","); StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("超過10天自動確認收貨,logisticsId:" + item[0] + ",userId:" + item[1]); orderService.confirmReceive(Long.valueOf(item[0]), Long.valueOf(item[1])); stringBuffer.append(",成功!"); logger.info(stringBuffer.toString()); } } } }