redis分布式锁实现案例之redisson和StringRedisTemplate

Java高并发实战:从synchronized到Redisson分布式锁的演进与秒杀案例 在分布式系统和高并发场景中,并发控制是确保数据一致性的核心技术。其核心原理在于通过锁机制协调多个线程或服务对共享资源的访问,防止竞态条件导致的数据错乱。这项技术的核心价值在于,它能在保证数据强一致性的同时,兼顾系统的可用性与性能,是构建电商秒杀、库存扣减、金融交易等关键业务系统的基石。具体到Java技术栈,开发者通常从JVM内置的synchronized锁入手,解决单机并发问题;而在服务分布式部署时,则需借助基于Redis的分布式锁来实现跨进程协调。其中,Redisson框架因其提供的可重入锁、自动续期(看 阅读详情

redis实现分布式锁,单机情况下加synchronize关键字就ok了~,但是分布式情况下就会出现问题,一个简单的扣减库存问题来做分布式锁的demo~~

1、先添加pom依赖,我这里就将redis和redisson的依赖一起引入了

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

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.6.5</version>
        </dependency>

2、构建yml配置文件,添加redis配置,这只是为了redis配置的,redisson框架不需要,后面需要用到改端口号,起两个服务来做分布式环境下测试~

server:
  port: 8081

spring:
  # Redis 配置
  redis:
    database: 0  #数据库索引(默认为0)
    host: 127.0.0.1
    port: 6379  #默认链接端口
    password:  #默认为空
    jedis:
      pool:
        max-active: 8 #最大链接池
        max-wait: -1 #最大阻赛等待时间(使用负值没有限制)默认为-1
        max-idle: 8 #连接池中的最大空闲连接 默认 8
        min-idle: 0

3、构建主启动类

package com.king;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * created by king on 2020/6/8 11:45 上午
 */
@SpringBootApplication
public class LockRedisMain6633 {
    public static void main(String[] args) {
            SpringApplication.run(LockRedisMain6633.class,args);
        }
}

4、下面先放StringRedisTemplate的案例代码

package com.king.controller;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * created by king on 2020/6/8 8:01 下午
 */
@RestController
@Slf4j
public class RedisLockController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 1、加setIfAbsent是为了setnx来判断能不能获取锁
     * 2、加expire时间是为了防止宕机等情况造成死锁
     * 3、加value的equals判断是为了防止误删锁
     * 4、但是要是完全很好的实现分布式锁,还需要开启守护线程去动态续航expire时间,防止过期,下面引入了redisson框架,
     *    框架包含一个watchdog看门狗,可以去开启一个守护线程去动态续航
     * @return
     */
    @GetMapping("decreseStorage1/")
    public String decreaseStorage1() {
        String lockkey = "sku001";
        String value = Thread.currentThread().getName();
//        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, value);
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, value, 10, TimeUnit.SECONDS);
//        log.info("result:"+result);

        if (!result) {
            return "error";
        }
        try {
            int storage = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if (storage > 0) {
                int still = storage - 1;
                stringRedisTemplate.opsForValue().set("stock", still + "");
                System.out.println("扣减库存成功,目前库存剩余量为:" + still);
            } else {
                System.out.println("扣减库存失败,库存不足");
            }
        } finally {
            if (value.equals(stringRedisTemplate.opsForValue().get(lockkey))) {
                stringRedisTemplate.delete(lockkey);
            }
        }
        return "end";
    }


}

5、如果使用redisson框架来实现的话:

注意:要防止watchdog未生效问题

  •         redisson的自动续期,如果业务超长,运行期间自动续上30s,不用担心业务时间长,锁自动过期被删掉
  •         加锁得业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s后自动删除
  •         //lock.lock(10, TimeUnit.SECONDS);//10秒以后自动解锁,自动解锁时间一定要大于业务时间
  •         // lock.lock(10, TimeUnit.SECONDS)在锁时间到了以后,不会自动续期
  •         //1.如果我们传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认时间就是我我们传递的时间
  •         //2.如果我们未制定锁的超时时间,就使用lockWatchdogTimeout = 30 * 1000;看门狗默认时间
  •         //只要占锁成功,就会启动定时任务(重新给锁设置过期时间)新的时间就是看门狗的默认时间,每10秒,都会自动续期续成满时间
package com.king.controller;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * created by king on 2020/6/8 8:01 下午
 */
@RestController
@Slf4j
public class RedisLockController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private Redisson redisson;

    /**
     * 1、redisson框架实现分布式锁,自带watchdog看门狗
     *
     * @return
     */
    @GetMapping("decreseStorage/")
    public String decreaseStorage() {
        String lockkey = "sku001";
        //获取一把锁,只要锁的名字一样就是同一把锁
        RLock lock = redisson.getLock(lockkey);
 
       

        //2。加锁
        // lock.lock();
        //1).redisson的自动续期,如果业务超长,运行期间自动续上30s,不用担心业务时间长,锁自动过期被删掉
        //2).加锁得业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s后自动删除
        //lock.lock(10, TimeUnit.SECONDS);//10秒以后自动解锁,自动解锁时间一定要大于业务时间
        // lock.lock(10, TimeUnit.SECONDS)在锁时间到了以后,不会自动续期
        //1.如果我们传递了锁的超时时间,就发送给redis执行脚本,进行站锁,默认时间就是我我们传递的时间
        //2.如果我们危制定锁的超时时间,就使用lockWatchdogTimeout = 30 * 1000;看门狗默认时间
        //只要站锁成功,就会启动定时任务(重新给锁设置过期时间)新的时间就是看门狗的默认时间,每10秒,都会自动续期续成满时间


        lock.lock(30,TimeUnit.SECONDS);
        try{
            int storage = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if (storage > 0) {
                int still = storage - 1;
                stringRedisTemplate.opsForValue().set("stock", still + "");
                System.out.println("扣减库存成功,目前库存剩余量为:" + still);
            } else {
                System.out.println("扣减库存失败,库存不足");
            }
        } finally {
            lock.unlock();
        }
        return "end";
    }

6、进行测试,先准备测试环境,

①、启动8081和8082两个端口,即修改端口启动微服务

②、配置host ip redislock.com ,并配置nginx的配置文件设置反向代理微服务8081和8082,并实现负载均衡

upstream redis {   
         server 192.168.0.153:8081 weight=1 ;   
         server 192.168.0.153:8082 weight=1 ;
    }


    
     server{
        listen 80;
        charset utf-8;
        server_name redislock.com;

        location  ~* \.(php|jsp|cgi|asp|aspx)$
            {
                proxy_pass http://redis;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header REMOTE-HOST $remote_addr;
            }

        location /
            {
                proxy_pass http://redis;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header REMOTE-HOST $remote_addr;

                add_header X-Cache $upstream_cache_status;
                
                #Set Nginx Cache
                
                    add_header Cache-Control no-cache;
            }

     }

③、启动jmeter压测软件,进行配置请求来测试会不会超卖等情况

④、查看控制台打印结果,发现两种情况都能控制住扣减库存的问题,而且也在扣减完库存后将锁删掉了~

 

 

Redis 实现分布式锁:原理、实现与注意事项(Redisson 之外的轻量级方案) 本文介绍了基于Redis实现分布式锁的轻量级方案,重点讲解了分布式锁的核心要求(互斥性、防死锁、解锁安全等)和Redis实现优势。通过分析三种实现方案的演进过程,指出SETNX+EXPIRE组合的缺陷,推荐使用Redis 2.6.12+的SET NX EX原子指令。文章提供了完整的生产级Java实现代码,包含带详细注释的加锁和解锁逻辑,其中解锁采用Lua脚本确保原子性和安全性。该方案相比Redisson更轻量透明,适合中小型项目使用,并可作为理解分布式锁底层原理的实践案例。 阅读详情

相关推荐

7-1、Redis Redisson分布式锁实战(含Spring Boot)

在【Redis Jedis实战(含Spring Boot)】基础上做如下修改: 1、子pom.xml 添加redisson依赖 <!-- <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</art...

java爱分享 1031

RedisTemplate 常用方法,序列化方式,分布式锁,工具类封装、商品秒杀、禁用Keys推荐Scan

目录 RedisTemplate 常用方法 RedisTemplate 序列化方式 RedisTemplate 常用方法 org.springframework.data.redis.core.RedisTemplate 常用方法(本文环境 Spring Boot 2.1.3): 方法 描述 Boolean expire(K key, final long timeout, f...

蚩尤后裔-汪茂雄 7803

Redis分布式锁实现及原理

实现redis分布式锁及原理 单体架构 中 synchronized 只是本地锁,锁的也只是当前jvm下的对象,在分布式场景下,要用分布式锁。 1.在高并发场景多个用户访问服务器,在redis那里同时会接收到多个请求,这个时候就需要在访问服务的redis那里加个锁就可以了,多个服务器谁拿到锁,哪个服务就执行,其他服务就进行等待直到获取锁。 服务器1要去访问redis,那么他会在red...

大道至简,悟在天成。 1687

基于RedisTemplate和Redisson的redis分布式锁(2021)

基于RedisTemplate和Redisson两种方式完成了redis分布式锁, 以及注解实现

(๑•̀ㅂ•́)و✧ 不努力未来永远只是个梦 7280

HFSS初学笔记(二)——75Ω带状线设计

本文利用HFSS软件设计并优化了一条75Ω的带状线结构,通过调整几何参数和介质材料,实现了精确的阻抗控制。仿真结果显示,该带状线在高频信号传输中的表现优越,具有良好的S参数、低插入损耗和极小的信号反射损耗。

2401_87464239的博客 4541

Python、Selenium实现问卷星自动填写(内含适配个人问卷的方法)

使用Python、Selenium实现问卷星自动填写,内含适配个人问卷的方法。

DaenCode的博客 3837

springboot集成redis 分布式锁(redistemplate,lua,redisson)

springboot集成redis 分布式锁(redistemplate,lua,redisson)

jun2571的博客 5261

C语言—for循环打印矩形,正三角形,倒三角形,九九乘法,等腰三角形,倒着的等腰三角形(简易版代码)(重点考察for循环嵌套)

本章节教大家如何利用for循环打印正三角形,倒三角形,九九乘法表及等腰三角形(简易版代码)说明:1、循环语句的循环体内又包含另一个完整的循环结构,称为循环结构的嵌套。内嵌的循环语句中还可以再嵌套循环结构,这样就形成多重循环结构的嵌套。2、for 语句、while 语句和 do-while 语句都允许嵌套。三种循环语句可以相互嵌套。3、内层的循环语句必须完全被包含在外层的循环体中,不能发生交叉。

m0_63501145的博客 1695

RedisTemplate、StringRedisTemplate、序列化器配置

stringRedisTemplate、RedisTemplate序列化,几种序列化器配置及性能对比,key、value分别序列化、lettuce和jedis

qq_73181349的博客 2772

STM32F103VET6实战:用W25Q64外部Flash实现Bootloader+Application双备份(含完整代码解析)

本文详细介绍了基于STM32F103VET6微控制器和W25Q64外部Flash实现Bootloader+Application双备份固件升级的完整方案。通过精心设计的Flash分区策略、可靠的Bootloader程序以及包含双重校验和自动回滚机制的升级流程,有效解决了远程升级过程中断电导致设备变砖的风险,确保了工业嵌入式系统的高可靠性与稳定性。

linux的博客 823

pytorch-cifar100学习资料汇总 - 基于PyTorch的CIFAR-100图像分类实践

pytorch-cifar100是一个基于PyTorch实现CIFAR-100数据集图像分类的开源项目。该项目实现了多种经典的深度学习网络模型,如ResNet、DenseNet、VGG等,为开发者提供了在CIFAR-100数据集上进行图像分类实验的代码范例。pytorch-cifar100项目为我们提供了在CIFAR-100数据集上进行图像分类实验的完整代码实现。无论你是想要学习PyTorch的使用,还是研究不同网络模型在CIFAR-100上的表现,这个项目都是一个很好的起点。

helloaiworld的博客 1123

【Redis】RedisTemplate和StringRedisTemplate的区别

RedisTemplate 看这个类的名字后缀是 Template ,如果了解过 Spring 如何连接关系型数据库的,大概不会难猜出这个类是做什么的 ,它跟 JdbcTemplate 一样封装了对Redis的一些常用的操作,当然 StringRedisTemplate 跟 RedisTemplate 功能类似那么肯定就会有人问,为什么会需要两个Template呢,一个不就够了吗?,如果需要自定义序列化配置,可以自己写一个 RedisTemplate 的Bean,来完成配置。那么就可以得出一个结论,

Mr_VK的博客 3188

电源完整性之Cadence Sigrity Power SI_AC阻抗仿真

之前和大家分享过电源完整性之仿真设计原理链接: [link](https://blog.youkuaiyun.com/weixin_41808082/article/details/117065140?spm=1001.2014.3001.5501).今天接着上一篇文章总结一下电源AC阻抗的的仿真操作流程及一些simulation中的设置参数,用到的时候Cadence Sigrity 中的Power SI组件,下面开始享受仿真的快乐吧: 1.仿真模式选择与文件导入 选择Cadence Sigrity下的Power SI

刘小同学的博客 1万+

redis作为分布式锁,redis重点面试题

redis作为分布式锁redis的应用场景。采用Redis的官方推荐的Redisson作为redis的分布式锁redis重点面试题 redis的应用场景。 (1)作为缓存 (2)分布式锁 今天就来介绍分布式锁的使用场景。 采用Redis的官方推荐的Redisson作为redis的分布式锁 用redis实现分布式锁,解决高并发时的线程安全问题 Redis提供一些命令SETNX,GETSET,可以方便实现分布式锁机制。以下是常用的一些命令: ①SETNX key value:当且仅当 key 不存在,将 ke

同一片天空 1718

《Autosar从入门到精通-实战篇》总目录_培训教程持续更新中...

欢迎大家订阅《Autosar从入门到精通-实战篇》,下方整理了相关博文的目录(单击蓝色字体即可跳转),方便大家获取。 本专栏旨在:扫除Autosar工具链配置过程中的障碍,加深对Autosar理论的理解。 温馨提醒: 如有疑问,可在博文的“评论区”给小编留言,进行技术交流(评论区开启了验证功能,审核通过后,会显示); 如有疑问,也可以通过博文中的第一个图片联系小编,获取专栏/博文的实时状态; 由于工作限制,仅做个人技术交流。添加好友时,请备注您的“姓名-公司-职务...

「汽车电子助手」的博客 12万+

基于QT与STM32的电力参数采集系统(华为云IOT)(211)

本项目构建一款集多功能于一体的电力参数采集系统,该系统以高性能、低功耗的STM32F103RCT6微控制器为核心,集成多种传感器与通信模块,实现对电力设施如电压、电流、功率、电能及环境温度等关键参数的实时精确采集,并通过GPS模块获取设备地理位置信息,满足了电力设备状态全面监控的需求。

2902

Redis分布式锁实现

如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

учёба 2411

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SpringBoot中使用Redis实现分布式锁

SpringBoot中使用Redis实现分布式锁:使用StringRedisTemplate实现、使用Redisson实现。

weixin_42113716的博客 2888

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Redis实现分布式锁方法详细

在单体应用中,如果我们对共享数据不进行加锁操作,会出现数据一致性问题,我们的解决办法通常是加锁。

weixin_47148475的博客 3108

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Spring Boot 操作 Redis 的各种实现

共同点:都提供了基于Redis操作的Java API,只是封装程度,具体实现稍有不同。不同点:1.1、Jedis是Redis的Java实现的客户端。支持基本的数据类型如:String、Hash、List、Set、Sorted Set。特点:使用阻塞的I/O,方法调用同步,程序流需要等到socket处理完I/O才能执行,不支持异步操作。Jedis客户端实例不是线程安全的,需要通过连接池来使用Jedis。优点点:分布式锁,分布式集合,可通过Redis支持延迟队列。

2501_90392009的博客 824

Redis分布式锁的正确使用姿势

分布式锁在日常开发中,用处非常的多。包括但不限于抢红包,秒杀,支付下单,幂等,等等场景。分布式锁的实现方式有多种,包括redis实现,mysql实现,zookeeper实现等等。而其中redis非常适合作为分布式锁使用,并且在各个公司都大规模的使用。本文将由浅入深的探究Redis分布式锁的实现,最终实现一个可工业使用的Redis分布式锁。欢迎大家一步一步跟读,一起学习一起进步。分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。

javallllllllllll的博客 1631

Rydr抢单分布式锁实战:Redis、MySQL、Redisson、RedLock五种方案深度对比

**Rydr** 是一个基于 **Spring Cloud 微服务**构建的完整网约车平台,其中最经典的并发场景就是**司机抢单**:一个订单推送出去后,成百上千个司机同时点击"抢单",如何保证**一单只被一个司机抢走**?这正是**分布式锁**要解决的核心问题。本项目在订单服务中直接实现了 5 种抢单方案:**无锁、JVM 锁、MySQL 锁、Redis 锁、Redisson 锁 + RedLo

gitblog_01032的博客 393

Redis分布式锁实战:SETNX、Redisson与Lua脚本方案深度解析

在分布式系统中,锁是实现资源互斥访问、保障数据一致性的核心机制。其基本原理是通过一个所有服务节点都能访问的中间件,在并发场景下确保同一时刻只有一个客户端能执行关键操作。Redis凭借其高性能和原子操作,成为实现分布式锁的主流技术选型,为高并发场景如秒杀、库存扣减提供了可靠的技术支撑。SETNX命令结合EXPIRE是实现锁的基础,但需注意原子性风险;Redisson客户端通过看门狗机制提供了自动续期和高可靠性;而Lua脚本方案则通过原子执行保证了操作的一致性。本文结合实战经验,深入剖析这三种主流方案的实现原理

weixin_30699955的博客 299

redis + redission: 实现分布式锁

你设置了 30 秒过期,但数据库查询很慢,业务执行了 35 秒。如果所有商品共用一把锁,用户 A 买商品 1 时,用户 B 买商品 2 也会被阻塞,系统吞吐量急剧下降。既然 Redis 是所有实例都能访问的,最直观的思路就是:用 Redis 的一个 Key 来表示锁。如果业务执行了 35 秒,第 30 秒锁自动过期,另一个实例拿到锁,两个实例同时执行业务。分布式锁,就是让多个不同机器、不同 JVM 的服务实例,也能够竞争同一把锁。,如果锁已经被 Redis 自动过期删除了,另一个实例又创建了新锁,你的。

qq_31532983的博客 387

基于Redisson实现Redis分布式锁

基于Redisson实现Redis分布式锁 https://riemann.blog.youkuaiyun.com/article/details/104763755 @Controller public class RedisLockController { private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockController.class); @Resource private RedissonCl

你的才华撑不起野心时,静下心学习;你的能力驾驭不了目标时,沉下心努力 484

redis分布式锁的实现

redis分布式锁的实现 1.依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2.代码 ...

qq_42513284的博客 250
上一篇: docker 常用命令
下一篇: 利用工厂模式+策略模式替换if else判断案例演示
TOP__ONE
博客等级 码龄10年 74粉丝 117原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值