在分布式环境中,可以使用Redis作为分布式锁。如图所示:
实现原理
在Redis中可以使用如下命令实现Redis的分布式锁。
1)setnx key value
SETNX key value
解释
SETNX 是"set if not exist"的缩写。即如果不存在则设置一个key值,存在则不执行任何操作。
返回值
1或0,存在返回0,不存在返回1。
例子
redis 127.0.0.1:6379> SETNX mykey redis
(integer) 1
redis 127.0.0.1:6379> SETNX mykey mongodb
(integer) 0
redis 127.0.0.1:6379> GET mykey
"redis"
2)setex key timeout value
setex key timeout value
解释
Redis SETEX 命令用于在 redis key 中设置一些指定超时时间的字符串值,以秒为单位。
返回值
成功返回OK。
示例
127.0.0.1:6379> SETEX mykey 60 redis
OK
127.0.0.1:6379> ttl mykey
(integer) 51
127.0.0.1:6379> get mykey
"redis"
注意:Redis的操作是原子性的,set值和过期时间是在同一时间内完成。
总结:Redis中的分布式锁的原理是,设置一个带有过期时间的key,如果设置成功则表示占用锁成功,否则占用锁失败。
使用Redisson实现分布式锁
在Java开发中,我们可以使用Redisson实现分布式锁,这里介绍Redisson的简单使用方法。
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.18.1</version>
</dependency>
2)启动Redis,默认端口6379,不需要配置任何配置文件。启动项目:
启动成功,监听Redis默认端口6379。当然也可以自定义ip和port配置如下
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.config.TransportMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.setTransportMode(TransportMode.NIO);
SingleServerConfig singleServerConfig = config.useSingleServer();
singleServerConfig.setAddress("redis://127.0.0.1:6379");
singleServerConfig.setPassword("123456");
RedissonClient redisson = Redisson.create(config);
return redisson;
}
}
3)接下来,写一个处理逻辑Controller,获取Redis的分布式锁。
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.TimeUnit;
@Controller
public class RedisLockController {
@Autowired
private RedissonClient redissonClient;
@ResponseBody
@GetMapping("/home")
public String home(){
String lockKey = "YXJC123_COM";
RLock rLock = redissonClient.getLock(lockKey);
try {
long waitTimeout=100,leaseTime=100;
boolean res = rLock.tryLock(waitTimeout, leaseTime, TimeUnit.SECONDS);
if (res) {
//获取Redis分布式锁成功
}
} catch (Exception e) {
throw new RuntimeException("获取Redis分布式锁失败");
}finally{
//释放锁
rLock.unlock();
}
return "welcome";
}
}