<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> <version>2.1.6.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
spring-boot-starter-data-redis:
在低版本中默认依赖 Jedis
在高版本中默认依赖 lettuce,若要使用Jedis 则须要修改依赖(如上所示)java
application.properties 或者 application.yml 均可以(只是有格式的区别,做用并没有差异)redis
spring.redis.host=127.0.0.1 spring.redis.database=0 spring.redis.port=6379 spring.redis.jedis.pool.max-active=8 spring.redis.jedis.pool.max-wait=-1 spring.redis.jedis.pool.max-idle=8 spring.redis.jedis.pool.min-idle=0 spring.redis.password=redis123456
package com.uzhizhe.user.cache; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import redis.clients.jedis.Jedis; import java.util.Collections; /** * @Desc Redis service * @Author uzhizhe */ @Service @Slf4j public class RedisService { /** * 操做成功 */ private static final Long RELEASE_SUCCESS = 1L; /** * 操做成功 */ private static final String LOCK_SUCCESS = "OK"; /** * 不存在才set */ private static final String SET_IF_NOT_EXIST = "NX"; /** * 毫秒单位 */ private static final String SET_WITH_EXPIRE_TIME = "PX"; /** * 释放分布式锁的Lua 脚本 */ private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; /** * 默认分布式锁过时时间 */ private static final Integer DEFALUT_EXPIRE_TIME = 5000; /** * redisTemplate */ @Autowired private StringRedisTemplate redisTemplate; /** * 获取分布式锁 * * @param lockKey 加锁键 * @param requestId 加锁客户端惟一标识(采用UUID) * @param expireTime 锁过时时间, 单位:毫秒 * @return 获取锁成功或者失败 */ public boolean tryLock(String lockKey, String requestId, long expireTime) { return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); return LOCK_SUCCESS.equals(result); }); } /** * 释放分布式锁 * * @param lockKey lockKey * @param requestId requestId 加锁时的惟一ID * @return 释放锁成功或者失败 */ public boolean releaseLock(String lockKey, String requestId) { return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); Object result = jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(lockKey), Collections.singletonList(requestId)); return RELEASE_SUCCESS.equals(result); }); } }
利用redis 的set方法实现加锁
1. set 的5个参数,可以很好的保证加锁的正确性
2. 过时时间:保证不会出现死锁,在没有主动释放时,会因过时释放
3. 设置Value值,保证本身的锁不会被别人释放(所谓:解铃还须系铃人)
4. Redis 命令的原子性,保证了锁的互斥性spring