Spring Boot使用Redis和Redission实现分布式锁的demo

分布式锁

分布式锁,即分布式系统中的锁。随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。

下面主要介绍springboot集成redis和Redission实现分布式锁。

1.引入依赖

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

2.配置信息

spring:
  application:
    name: demo-server
 
  # dynamic数据源配置
  datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver # mysql版本为5.x使用该配置: com.mysql.jdbc.Driver,8.0版本使用:com.mysql.cj.jdbc.Driver
     url: jdbc:mysql://localhost:3306/ftdb0?useUnicode=true&autoReconnect=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
     username: root
     password: 123

  # Redis配置
  data:
    redis:
      # 主从模式配置
      cluster:
        nodes:
          - 127.0.0.1:7003
          - 127.0.0.1:7001
          - 127.0.0.1:7002
          - 127.0.0.1:7102
          - 127.0.0.1:7202
          - 127.0.0.1:7302
          - 127.0.0.1:7101
          - 127.0.0.1:7201
          - 127.0.0.1:7301
          - 127.0.0.1:7401
          - 127.0.0.1:7402
  # 单机配置
#      host: 127.0.0.1
#      port: 6379
#      password: 11
  redisson:
  # 单机配置
#    address: 127.0.0.1:6379
#    password: 12345
    # 主从模式配置
    clusterServersConfig:
      # 只在从服务节点里读取
      readMode: "SLAVE"
      # 订阅模式,主节点读取
      subscriptionMode: "MASTER"
        # 主节点信息
      nodeAddresses:
          - "redis://127.0.0.1:7001"
          - "redis://127.0.0.1:7101"
          - "redis://127.0.0.1:7102"
          - "redis://127.0.0.1:7002"
          - "redis://127.0.0.1:7201"
          - "redis://127.0.0.1:7202"
          - "redis://127.0.0.1:7003"
          - "redis://127.0.0.1:7302"
          - "redis://127.0.0.1:7301"
          - "redis://127.0.0.1:7401"
          - "redis://127.0.0.1:7402"
        #集群扫描间隔时间 单位毫秒
      scanInterval: 1000

3.Redis配置类

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.DefaultBaseTypeLimitingValidator;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
public class RedisConfig {
    private final RedisConnectionFactory redisConnectionFactory;
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        ObjectMapper mapper = new ObjectMapper().
                activateDefaultTyping(new DefaultBaseTypeLimitingValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY).
                setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(mapper, Object.class);
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

Redisson实现分布式锁

package com.demo.server.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.common.exception.CommonException;
import com.demo.common.vo.UserTest;
import com.demo.server.mapper.UserTestMapper;
import com.demo.server.service.UserTestService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
public class UserServiceImpl extends ServiceImpl<UserTestMapper, UserTest> implements UserTestService {

    private final RedissonClient client;

    @Override
    public int lockTest(long id) {
        RLock lock = client.getLock("lock:user:" + id);
        try {
            // 尝试获取锁,最多等待1秒,上锁以后5秒自动解锁
            boolean locked = lock.tryLock(1, 5, TimeUnit.SECONDS);
            if (locked) {
                return baseMapper.lockTest(id);
            }
            throw new RuntimeException("获取锁失败");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        finally { // 这里可以在测试时注释掉,不然会无法看到效果,也可以不用,因为在锁里面已经释放了
            // 如果是当前线程持有,释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }
}

Redis实现分布式锁

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.common.exception.CommonException;
import com.demo.common.vo.UserTest;
import com.demo.server.mapper.UserTestMapper;
import com.demo.server.service.UserTestService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
public class UserServiceImpl extends ServiceImpl<UserTestMapper, UserTest> implements UserTestService {
    
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public int lockTest1(long id) {
        // 尝试获取锁
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent("lock:user:" + id, id, 30L, TimeUnit.SECONDS);
        if (Objects.equals(ifAbsent, Boolean.TRUE)) {
            UserTest byId = baseMapper.selectById(id);
            Optional.ofNullable(byId).ifPresent(userTest -> {
                if (userTest.getAge() <= 0) {
                    throw new RuntimeException("不能是负数");
                }
            });
            return baseMapper.lockTest1(id);
        }
        throw new RuntimeException("获取锁失败");
    }
}


简单demo,简单测试。更多使用Redis实现分布式锁了解可以查看该大佬详细文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值