SpringBoot整合Redis实现分布式锁

SpringBoot整合Redis实现分布式锁

分布式系统为什么要使用分布式锁?

首先,分布式系统是由多个独立节点组成的,这些节点可能运行在不同的物理或虚拟机器上,它们通过网络进行通信和协作。在这样的环境中,多个节点可能同时尝试访问和修改共享资源,这就可能导致数据不一致和并发冲突的问题。

为了解决这个问题,分布式锁被引入作为一种同步机制。分布式锁能够在分布式系统中提供全局唯一的锁,确保在任意时刻只有一个节点能够访问和修改共享资源。当节点需要访问共享资源时,它必须先获取分布式锁,如果锁已经被其他节点持有,则当前节点需要等待或执行其他操作。只有当节点成功获取到锁后,才能对共享资源进行访问和修改。

此外,分布式锁还可以帮助实现一些复杂的分布式系统需求,如分布式事务、分布式缓存一致性等。通过使用分布式锁,我们可以更好地控制并发访问,保证数据的一致性和完整性,提高系统的可靠性和稳定性。

实现分布式锁需要考虑到多种因素,如锁的粒度、锁的公平性、锁的释放机制等。同时,由于分布式系统的复杂性和不确定性,分布式锁的实现也可能存在一些挑战和限制,如网络延迟、节点故障等问题都可能导致锁的行为变得复杂和难以预测。因此,在使用分布式锁时,我们需要根据实际情况进行权衡和选择,确保能够满足系统的需求并避免潜在的问题。

分布式系统使用分布式锁是为了实现资源的同步访问和并发控制,保证数据的一致性和完整性,提高系统的可靠性和稳定性。

redis配置类

java 复制代码
package com.test.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2023-06-09 10:58
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

}

分布式锁工具类

java 复制代码
package com.test.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-03-08 14:33
 */
@Component
public class RedisDistributedLock {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {
        return stringRedisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean releaseDistributedLock(String lockKey, 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 = stringRedisTemplate.execute(
                new DefaultRedisScript<Long>(script, Long.class),
                Collections.singletonList(lockKey),
                requestId);
        System.out.println(result);
        return result.equals(1L);
    }
}

定时任务测试分布式锁

java 复制代码
package com.test.service;

import com.test.config.RedisDistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-03-08 14:44
 */
@Service
public class TestService {

    @Autowired
    private RedisDistributedLock redisDistributedLock;

    @Scheduled(cron = "0/10 * * * * ?")
    //@Scheduled(cron = "0 10 16 * * ?")
    @Transactional(rollbackFor = Exception.class)
    public void testLock(){
        System.out.println("进入分布式锁方法");
        // 尝试获取分布式锁
        if (redisDistributedLock.tryGetDistributedLock("tangshuai", "123", 30)) {
                System.out.println("释放分布式锁");
                redisDistributedLock.releaseDistributedLock("tangshuai", "123");
        } else {
            // 未能获取到锁,可以选择重试或返回失败
            throw new RuntimeException("未能获取到锁,请重试");
        }
    }
}

分别启动两个相同的服务

java 复制代码
package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2023-06-08 17:04
 */
@SpringBootApplication
@EnableScheduling
public class SaTokenDemoApp {
    public static void main(String[] args) {
        SpringApplication.run(SaTokenDemoApp.class, args);
    }
}

查看两个控制台打印情况,两个服务谁谁拿到锁,谁开始执行业务代码,没拿到锁的服务抛出异常


相关推荐
qq_12498707533 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_3 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_818732063 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
此生只爱蛋3 小时前
【Redis】主从复制
数据库·redis
汤姆yu7 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶7 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip8 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
惊讶的猫8 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
JavaGuide8 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
期待のcode8 小时前
Redis的主从复制与集群
运维·服务器·redis