ChatGPT 用redis实现分布式锁

Posted 赖斯啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ChatGPT 用redis实现分布式锁相关的知识,希望对你有一定的参考价值。

背景

打算基于springboot、RedisTemplate,由ChatGPT来实现分布式锁,记录全过程。

基础介绍




基于RedisTemplate实现分布式锁

基于springboot及RedisTemplate实现分布式锁
在Spring Boot中,我们可以通过RedisTemplate来使用Redis的分布式锁机制。下面是一个基于RedisTemplate的简单实现:

@Service
public class DistributedLockService 
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    public boolean acquire(String lockKey, String requestId, long expireTime) 
        // 使用setnx命令尝试获取锁
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
        return result != null && result;
    
    
    public void release(String lockKey, String requestId) 
        String currentValue = redisTemplate.opsForValue().get(lockKey);
        // 如果当前锁的值与请求锁的值相等,则删除锁
        if (currentValue != null && currentValue.equals(requestId)) 
            redisTemplate.delete(lockKey);
        
    
    


上述代码中,我们通过RedisTemplate的opsForValue方法来获取一个ValueOperations对象,然后使用setIfAbsent方法来尝试获取锁。如果返回值为true,说明当前进程或线程成功获得了锁;否则说明其他进程或线程已经获得了锁。在释放锁时,我们通过get方法获取锁的值,如果该值与请求锁的值相等,则说明当前进程或线程持有锁,可以删除锁。由于获取锁和释放锁的操作都是原子的,因此可以避免死锁和竞争等问题。

需要注意的是,上述实现仅仅是一个简单的示例,实际应用中还需要考虑到锁的可重入性、锁的超时处理、锁的多进程竞争等问题,否则可能会导致锁无法正常释放或者产生其他问题。因此,在实际开发中,需要仔细考虑锁的实现细节,并进行充分测试。

基于springboottest写单元测试

好的,这里是一个基于SpringBootTest框架的单元测试示例,它测试了DistributedLockService的基本功能:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
public class DistributedLockServiceTest 

    @Autowired
    private DistributedLockService lockService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void testAcquireLock() 
        String lockKey = "test-lock";
        String requestId = "request-id";

        // 尝试获取锁
        boolean result = lockService.acquire(lockKey, requestId);

        // 验证结果
        assertTrue(result);
        assertNotNull(redisTemplate.opsForValue().get(lockKey));
    

    @Test
    public void testReleaseLock() 
        String lockKey = "test-lock";
        String requestId = "request-id";

        // 获取锁
        redisTemplate.opsForValue().set(lockKey, requestId, 30, TimeUnit.SECONDS);

        // 尝试释放锁
        lockService.release(lockKey, requestId);

        // 验证结果
        assertNull(redisTemplate.opsForValue().get(lockKey));
    


在上述测试中,我们使用了@SpringBootTest注解来启动Spring Boot上下文,并自动注入了DistributedLockService和RedisTemplate。然后,我们分别测试了acquire和release方法。在testAcquireLock方法中,我们尝试获取锁并验证了锁的值不为null。在testReleaseLock方法中,我们先获取了锁,然后尝试释放锁并验证了锁的值为null。注意,在testReleaseLock方法中,我们使用了redisTemplate.opsForValue().set(lockKey, requestId, 30, TimeUnit.SECONDS)来手动设置锁的过期时间,因为在DistributedLockService中并没有实现自动续期的功能。

说明

实现的分布式锁,没有去处理可重入、没有考虑锁的续期。

总结

个人体验总结,ChatGPT整体结果方向不差,细节容易出错,需要我们加入各种条件和引导,通过引导可以改正给出的结果,我觉得ChatGPT做得能够更好,或者从另一个方面讲,我们能够掌握方法更高效地去引导。

用redis实现分布式锁

  用一个redis 实现分布式锁。

1.为什么要用reids 实现分布式锁(比较于syschronized 的优势) : 既然是分布式锁于syschronized 的优势 就在于分布式可用。java 提供的syschronized,lock(syschronized,lock内存语义不同.以后会写)等但是只适用于一个服务器。

 

www.redis.cn 中文redis网站。

 

本次实现redis分布式锁的几个  redis 命令。

SETNX :key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写

GETSET:自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。

 

代码:

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
@Slf4j
public class RedisLock {

@Autowired
private StringRedisTemplate redisTemplate;

/**
* @param key 订单id
* @param value 当前时间+超时时间
* @return
*/
public synchronized boolean lock(String key,String value){
//对应的是reids 中的SETNX命令 设置成功为true
if(redisTemplate.opsForValue().setIfAbsent(key, value)){
return true;
}
      
      //下面的意义是解决 当我们加锁后由于代码或者网络的原因中间抛出异常未能正常解锁
String currentValue = redisTemplate.opsForValue().get(key);

if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue)<System.currentTimeMillis()){

//获取上一个锁的时间
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if(oldValue != null && oldValue.equals(currentValue)){
return true;
}
}

return false;
}

/**
* 解锁
* @param key
* @param value
*/
public void unlock(String key, String value){

try {
        
String currentValue = redisTemplate.opsForValue().get(key);

if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【redis分布式锁解锁异常】,{}",e );
}


}
}

 

我用的是springBoot 2.0.5版本的

<!--redis依赖--> 
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<[email protected]依赖--> 
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

 

 

 

GETSET





































































以上是关于ChatGPT 用redis实现分布式锁的主要内容,如果未能解决你的问题,请参考以下文章

用redis实现分布式锁

《Redis官方文档》用Redis构建分布式锁

大厂面试题详解:如何用Redis实现分布式锁?

redis 分布式锁

Redis分布式锁的实现原理

Redis分布式锁的实现原理