spring cloud 用redis做分布式锁(解决分布式多节点情况下,定时任务多次执行)

 我们知道现在微服务很流行,为此,许多中小型企业都将自己以前的框架加以改造,其中以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());

         }
      }
   }
}

 

posted @ 2019-10-22 15:11  蜗牛的信仰  阅读(3145)  评论(0编辑  收藏  举报