Redis를 사용하여 분산 잠금 구현
redis 기능 소개
1. String, List, Map, Set, ZSet 등과 같은 유형입니다.
2. 데이터 지속성, RDB 및 AOF 방법 지원
3. 클러스터 작업 모드, 강력한 파티션 내결함성 지원
4. 명령의 순차적 처리
5. 트랜잭션 지원
6. 게시 및 구독 지원
Redis는 SETNX 명령을 사용하여 분산 잠금을 구현합니다. 🎜#
SETNX 키 값키가 존재하지 않는 경우에만 키 값을 value로 설정합니다. 주어진 키가 이미 존재하는 경우 SETNX는 어떠한 조치도 취하지 않습니다. SETNX는 "SET if Not eXists"(존재하지 않으면 SET)의 약어입니다. 사용 가능한 버전: >= 1.0.0 시간 복잡도: O(1) 반환 값: 설정에 성공하면 1을 반환합니다. 설정하지 못했습니다. 0을 반환합니다.redis> EXISTS job # job 不存在 (integer) 0 redis> SETNX job "programmer" # job 设置成功 (integer) 1 redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败 (integer) 0 redis> GET job # 没有被覆盖 "programmer"
@Component public class RedisDao { @Autowired private RedisTemplate redisTemplate; @Resource(name="redisTemplate") private ValueOperations<Object, Object> valOpsObj; /** * 如果key不存在,就存储一个key-value,相当于SETNX命令 * @param key 键 * @param value 值,可以为空 * @return */ public boolean setIfObsent (String key, String value) { return valOpsObj.setIfAbsent(key, value); } /** * 为key设置失效时间 * @param key 键 * @param timeout 时间大小 * @param unit 时间单位 */ public boolean expire (String key, long timeout, TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 删除key * @param key 键 */ public void delete (String key) { redisTemplate.delete(key); } }
@RestController @RequestMapping("test") public class TestController { private static final Logger LOG = LoggerFactory.getLogger(TestController.class); //日志对象 @Autowired private RedisDao redisDao; //定义的分布式锁key private static final String LOCK_KEY = "MyTestLock"; @RequestMapping(value={"testRedisLock"}, method=RequestMethod.GET) public void testRedisLock () { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 5; i++) { executorService.submit(new Runnable() { @Override public void run() { //获取分布式锁 boolean flag = redisDao.setIfObsent(LOCK_KEY, "lock"); if (flag) { LOG.info(Thread.currentThread().getName() + ":获取Redis分布式锁成功"); //获取锁成功后设置失效时间 redisDao.expire(LOCK_KEY, 2, TimeUnit.SECONDS); try { LOG.info(Thread.currentThread().getName() + ":处理业务开始"); Thread.sleep(1000); //睡眠1000ms模拟处理业务 LOG.info(Thread.currentThread().getName() + ":处理业务结束"); //处理业务完成后删除锁 redisDao.delete(LOCK_KEY); } catch (InterruptedException e) { LOG.error("处理业务异常:", e); } } else { LOG.info(Thread.currentThread().getName() + ":获取Redis分布式锁失败"); } } }); } } }
/** * Redis访问工具类 */ @Component public class RedisDao { private static Logger logger = LoggerFactory.getLogger(RedisDao.class); @Autowired private StringRedisTemplate stringRedisTemplate; /** * 设置分布式锁 * @param key 键 * @param value 值 * @param timeout 失效时间 * @return */ public boolean setDistributeLock (String key, String value, long timeout) { RedisConnection connection = null; boolean flag = false; try { //获取一个连接 connection = stringRedisTemplate.getConnectionFactory().getConnection(); //设置分布式锁的同时为锁设置失效时间 connection.set(key.getBytes(), value.getBytes(), Expiration.seconds(timeout), RedisStringCommands.SetOption.SET_IF_ABSENT); flag = true; } catch (Exception e) { logger.error("set automic lock error:", e); } finally { //使用后关闭连接 connection.close(); } return flag; } /** * 查询key的失效时间 * @param key 键 * @param timeUnit 时间单位 * @return */ public long ttl (String key, TimeUnit timeUnit) { return stringRedisTemplate.getExpire(key, timeUnit); } } /** * 单元测试类 */ @RunWith(SpringRunner.class) @SpringBootTest public class Demo1ApplicationTests { private static final Logger LOG = LoggerFactory.getLogger(Demo1ApplicationTests.class); @Autowired private RedisDao redisDao; @Test public void testDistributeLock () { String key = "MyDistributeLock"; //设置分布式锁,失效时间20s boolean result = redisDao.setDistributeLock(key, "1", 20); if (result) { LOG.info("设置分布式锁成功"); long ttl = redisDao.ttl(key, TimeUnit.SECONDS); LOG.info("{}距离失效还有{}s", key, ttl); } } }
2019-05-15 13:07:10.827 - 设置分布式锁成功 2019-05-15 13:07:10.838 - MyDistributeLock距离失效还有19s
을 방문하세요. Redis 사용법 튜토리얼 컬럼 !
위 내용은 Redis를 사용하여 분산 잠금을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!