You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							103 lines
						
					
					
						
							3.2 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							103 lines
						
					
					
						
							3.2 KiB
						
					
					
				| package com.xiaomage.service; | |
| 
 | |
| 
 | |
| import com.xiaomage.enu.LockResultStatus; | |
| import com.xiaomage.enu.ResponseEnum; | |
| import com.xiaomage.exception.BizException; | |
| import com.xiaomage.vo.LockResult; | |
| import lombok.extern.slf4j.Slf4j; | |
| import org.redisson.api.RLock; | |
| import org.redisson.api.RedissonClient; | |
| import org.springframework.stereotype.Service; | |
| 
 | |
| import javax.annotation.Resource; | |
| import java.util.concurrent.TimeUnit; | |
| import java.util.function.Supplier; | |
| 
 | |
| /** | |
|  * 锁管理器 | |
|  * | |
|  * @author xiaomage | |
|  * @date 2022/12/25 | |
|  */ | |
| @Service | |
| @Slf4j | |
| public class LockManager { | |
| 
 | |
|     /** | |
|      * 最小锁等待时间 | |
|      */ | |
|     private static final int MIN_WAIT_TIME = 10; | |
| 
 | |
|     @Resource | |
|     private RedissonClient redisson; | |
| 
 | |
|     /** | |
|      * 加锁,加锁失败抛默认异常 - 操作频繁, 请稍后再试 | |
|      * | |
|      * @param key        加锁唯一key | |
|      * @param expireTime 锁超时时间 毫秒 | |
|      * @param waitTime   加锁最长等待时间 毫秒 | |
|      * @return LockResult  加锁结果 | |
|      */ | |
|     public LockResult lock(String key, long expireTime, long waitTime) { | |
|         return lock(key, expireTime, waitTime, () -> new BizException(ResponseEnum.COMMON_FREQUENT_OPERATION_ERROR)); | |
|     } | |
| 
 | |
|     /** | |
|      * 加锁,加锁失败抛异常 - 自定义异常 | |
|      * | |
|      * @param key               加锁唯一key | |
|      * @param expireTime        锁超时时间 毫秒 | |
|      * @param waitTime          加锁最长等待时间 毫秒 | |
|      * @param exceptionSupplier 加锁失败时抛该异常,传null时加锁失败不抛异常 | |
|      * @return LockResult  加锁结果 | |
|      */ | |
|     private LockResult lock(String key, long expireTime, long waitTime, Supplier<BizException> exceptionSupplier) { | |
|         if (waitTime < MIN_WAIT_TIME) { | |
|             waitTime = MIN_WAIT_TIME; | |
|         } | |
| 
 | |
|         LockResult result = new LockResult(); | |
|         try { | |
|             RLock rLock = redisson.getLock(key); | |
|             try { | |
|                 if (rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS)) { | |
|                     result.setLockResultStatus(LockResultStatus.SUCCESS); | |
|                     result.setRLock(rLock); | |
|                 } else { | |
|                     result.setLockResultStatus(LockResultStatus.FAILURE); | |
|                 } | |
|             } catch (InterruptedException e) { | |
|                 log.error("Redis 获取分布式锁失败, key: {}, e: {}", key, e.getMessage()); | |
|                 result.setLockResultStatus(LockResultStatus.EXCEPTION); | |
|                 rLock.unlock(); | |
|             } | |
|         } catch (Exception e) { | |
|             log.error("Redis 获取分布式锁失败, key: {}, e: {}", key, e.getMessage()); | |
|             result.setLockResultStatus(LockResultStatus.EXCEPTION); | |
|         } | |
| 
 | |
|         if (exceptionSupplier != null && LockResultStatus.FAILURE.equals(result.getLockResultStatus())) { | |
|             log.warn("Redis 加锁失败, key: {}", key); | |
|             throw exceptionSupplier.get(); | |
|         } | |
| 
 | |
|         log.info("Redis 加锁结果:{}, key: {}", result.getLockResultStatus(), key); | |
| 
 | |
|         return result; | |
|     } | |
| 
 | |
|     /** | |
|      * 解锁 | |
|      */ | |
|     public void unlock(RLock rLock) { | |
|         try { | |
|             rLock.unlock(); | |
|         } catch (Exception e) { | |
|             log.warn("Redis 解锁失败", e); | |
|         } | |
|     } | |
| 
 | |
| 
 | |
| }
 | |
| 
 |