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());

         }
      }
   }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM