Utilisation de Redis pour implémenter des verrous distribués
Introduction aux fonctionnalités de Redis
1. Prend en charge les types de données riches, tels que String, List, Carte, Set, ZSet, etc.
2. Prise en charge de la persistance des données, des méthodes RDB et AOF
3. Prise en charge du mode de fonctionnement du cluster, forte tolérance aux pannes de partition
4. >
5. Prise en charge des transactions6. Prise en charge de la publication et de l'abonnementRedis implémente des verrous distribués à l'aide de la commande SETNX : Valeur de clé SETNXDéfinissez la valeur de key sur value si et seulement si key n’existe pas. Si la clé donnée existe déjà, SETNX n'effectue aucune action. SETNX est l'abréviation de "SET if Not eXists" (s'il n'existe pas, alors SET). Versions disponibles : >= 1.0.0 Complexité temporelle : O(1) Valeur de retour : Défini avec succès, renvoie 1 . Échec de la définition, renvoyant 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
Tutoriel d'utilisation de Redis colonne !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!