java结合redistemplate使用分布式锁案例

在Java中使用RedisTemplate结合Redis来实现分布式锁是一种常见的做法,特别适用于微服务架构或多实例部署的应用程序中,以确保数据的一致性和避免竞态条件。以下是一个简单的使用Spring Boot和RedisTemplate实现分布式锁的案例。

1. 引入依赖

首先,确保你的Spring Boot项目中已经包含了Redis相关的依赖。如果是Maven项目,可以在pom.xml中添加如下依赖:

复制代码
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-data-redis</artifactId>  
</dependency>

2. 配置Redis

在application.properties或application.yml中配置Redis服务器的连接信息:

复制代码
# application.properties 示例  
spring.redis.host=localhost  
spring.redis.port=6379  
spring.redis.password= # 如果Redis设置了密码,请填写

3. 实现分布式锁

使用Redis实现分布式锁的关键在于利用Redis的原子操作(如SETNX或SET命令的NX、PX选项)来确保锁的互斥性。在Spring Boot中,我们可以通过自定义服务或使用RedisTemplate直接操作Redis。

下面是一个简单的分布式锁实现:

复制代码
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.core.script.DefaultRedisScript;  
import org.springframework.stereotype.Service;  
  
import java.util.Collections;  
import java.util.UUID;  
import java.util.concurrent.TimeUnit;  
  
@Service  
public class RedisLockService {  
  
    @Autowired  
    private RedisTemplate<String, Object> redisTemplate;  
  
    private static final String LOCK_PREFIX = "lock:";  
  
    /**  
     * 尝试获取锁  
     * @param key 锁的key  
     * @param expireTime 锁的过期时间,单位秒  
     * @return 是否获取锁成功  
     */  
    public boolean tryLock(String key, long expireTime) {  
        String requestId = UUID.randomUUID().toString();  
        String result = redisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX + key, requestId, expireTime, TimeUnit.SECONDS);  
        return "OK".equals(result);  
    }  
  
    /**  
     * 释放锁  
     * @param key 锁的key  
     * @param requestId 请求的唯一标识  
     * @return 是否释放锁成功  
     */  
    public boolean releaseLock(String key, String requestId) {  
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";  
        Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(LOCK_PREFIX + key), requestId);  
        return result != null && result > 0;  
    }  
}

4. 使用分布式锁

在你的业务逻辑中,可以这样使用RedisLockService:

复制代码
@Autowired  
private RedisLockService redisLockService;  
  
public void criticalSection() {  
    String lockKey = "yourLockKey";  
    try {  
        if (redisLockService.tryLock(lockKey, 10)) { // 尝试获取锁,10秒过期  
            // 执行你的关键代码  
            // ...  
        }  
    } finally {  
        redisLockService.releaseLock(lockKey, requestId); // 释放锁,requestId需要是之前尝试加锁时生成的UUID  
    }  
}

注意:这里的requestId需要是在尝试加锁时生成的,并在释放锁时使用相同的值。实际使用中,你可能需要在调用tryLock方法之前或方法中生成requestId,并在调用releaseLock时传递它。

5. 注意事项

  • 确保锁的粒度适中,避免过细或过粗的锁导致性能问题或并发限制。
  • 考虑锁的续期问题,特别是在长时间运行的操作中。
  • 在分布式系统中,锁失败是常态,确保你的代码能够妥善处理锁失败的情况。
相关推荐
小羊没烦恼!4 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里4 天前
java中的继承和多态的区别
java
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕4 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码4 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖4 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时4 天前
01-06-A-JVM排查实战详解
java·jvm
伞伞悦读4 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
vipxieliang4 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
C语言小火车4 天前
C/C++ 为什么需要编译器?
开发语言·c++