在分布式环境中,可以使用Redis作为分布式锁。如图所示:

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的简单使用方法。


1)maven安装,这里使用redisson-spring-boot-starter 3.18.1版本。

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.18.1</version>
</dependency> 

2)启动Redis,默认端口6379,不需要配置任何配置文件。启动项目:

SpringBoot + Redisson 启动

启动成功,监听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";
    }

}