在idea中高并发下的分布式锁以及解决方法

news2024/9/24 9:25:41

案例:1.互联网秒杀   2.抢优惠卷   3.接口幂

引入pom文件

 <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <!-- 实现分布式锁的工具类 -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.17.7</version>
        </dependency>
        <!-- Spring操作Redis的工具类 -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.3.2.RELEASE</version>
        </dependency>
        <!-- Redis客户端 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.9.0</version>
        </dependency>
        <!-- JSON解析工具 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <port>8001</port>
                    <!-- /表示访问应用的路径,省略项目名 -->
                    <path>/</path>
                    <!-- 配置编码方式为UTF-8 -->
                    <uriEncoding>UTF-8</uriEncoding>
                </configuration>
                <executions>
                    <execution>
                        <!-- 打包完成后,运行服务 -->
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

我们在pom文件中配置了打包后运行的jar包,所以我们要改变启动方式

 

在resources下创还能spring.xml的配置类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
        <context:component-scan base-package="com.leq"/>
            <!--  配置Redis连接工厂对象-->
         <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
             <property name="hostName" value="192.168.40.100"></property>
             <property name="port" value="6379"></property>
         </bean>
         <!--  Spring框架为了简化Redis操作提供了一个Redis操作的模板类:RedisTemplate-->
         <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
              <!--ref表示该属性的取值是引用类型,将ref取值设置为外部bean的id值-->
                <property name="connectionFactory" ref="connectionFactory"></property>
         </bean>


</beans>

 配置web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 配置解决中⽂乱码问题。此过滤器会进⾏:request.setCharacterEncoding("utf-8") -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

抢购的业务:

   @Autowired//简化Redis操作的模板类
    private StringRedisTemplate stringRedisTemplate;

   @RequestMapping("seckill")
    public synchronized String secKill(){
        String phone_count = stringRedisTemplate.opsForValue().get("phone_count");
        int phoneCount = Integer.parseInt(phone_count);
        if(phoneCount>0){
            //给redis中的数据添加锁  setnx()  在key不存在时,设置值
            phoneCount--;
            stringRedisTemplate.opsForValue().set("phone_count",String.valueOf(phoneCount));
       System.out.println("当前库存数量:"+phoneCount);
        }else {
            System.out.println("手机库存不足...");
        }

        return "当前的手机数量:"+phoneCount;
    } 

在一次性涌入大量数据的时候可能会出现-1或者同票的情况,这个时候就需要加锁 

  //RedissonClient实现分布式锁
    @Autowired
    private RedissonClient redisson;

    @RequestMapping("seckill")
    public synchronized String secKill(){
        //获取开发者自定义的锁
        RLock redissonLock = redisson.getLock("phone");
         //加锁,添加过期时间       1过期时间       2具体的单位    后面的代码都是受保护的
        redissonLock.lock(30, TimeUnit.SECONDS);
        Integer phoneCount = null;

        try {
            //高并发抢购业务
            String phone_count = stringRedisTemplate.opsForValue().get("phone_count");
            phoneCount = Integer.parseInt(phone_count);
            if(phoneCount>0){
                //给redis中的数据添加锁  setnx()  在key不存在时,设置值
                phoneCount--;
                stringRedisTemplate.opsForValue().set("phone_count",String.valueOf(phoneCount));
                System.out.println("当前库存数量-1:"+phoneCount);
            }else {
                System.out.println("手机库存不足...");
            }

        }catch (Exception e){
            System.out.println("有异常");
        }finally {
            redissonLock.unlock();//释放锁   释放后代码不受保护
        }
        return "当前的手机数量:"+phoneCount;
    }

 模拟一次性涌入大量数据:   

        1.打开ApiPost测试工具

        2.新建一个接口,访问刚刚写的seckil接口,点击保存

        3.保存后点击自动化测试,新建一个测试用例,点击最左边的HTTP请求接口,选择刚刚建的接口,在上面可以选择次数和时间,然后点击执行即可

      4.执行的结果如下,库存的数量需要我们自己手动在redis库中进行设置 :set phone_count 10

 

 

      

解决高并发就需要一个配置类RedissonConfig

//分布式锁的配置类

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//分布式锁配置类
@Configuration
public class RedissonConfig {
    //1.Redis单机模式下
    @Bean  //RedissonClient 是Redisson客户端对象,使用该对象来添加锁
    public RedissonClient singletonModelRedisson(){
        Config config =new Config();//构建Redis结构的配置
         //  Redis数据库默认放在字库1中,对应的下标为0
        config.useSingleServer().setAddress("redis://192.168.40.100:6379").setDatabase(0);
        return Redisson.create(config);
    }

  /*  // 2.Redis集群
    @Bean
    public RedissonClient clusterModelRedisson() {
        Config config =new Config();//构建Redis结构的配置
        config.useClusterServers()
                .setScanInterval(2000)//集群的扫描时间
                .addNodeAddress("redis://192.168.40.100:6379",
                        "redis://192.168.40.101:6379",
                        "redis://192.168.40.102:6379");
        return Redisson.create(config);
    }

    //3.Redis集群:主从架构
    @Bean
    public RedissonClient masterModelRedisson() {
        Config config =new Config();//构建Redis结构的配置
        config.useMasterSlaveServers()
                .setMasterAddress("redis://192.168.40.100:6379")
                .addSlaveAddress("redis://192.168.40.101:6379","redis://192.168.40.102:6379");
        return Redisson.create(config);
    }


    @Bean
    //4Redis集群:哨兵模式
    public RedissonClient sentinelModelRedisson() {
        Config config =new Config();//构建Redis结构的配置
        config.useSentinelServers()
        .addSentinelAddress("redis://192.168.40.101:6379","redis://192.168.40.102:6379","redis://192.168.40.100:6379");

        return Redisson.create(config);
    }
*/
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式软件架构——客户端缓存

浏览器的客户端缓存 当万维网刚刚出现的时候&#xff0c;浏览器的缓存机制差不多就已经存在了。在 HTTP 协议设计之初&#xff0c;人们便确定了服务端与客户端之间“无状态”&#xff08;Stateless&#xff09;的交互原则&#xff0c;即要求客户端的每次请求是独立的&#xff…

MySQL环境搭建(Windows电脑)

MySQL环境搭建-Windows电脑篇 软件获取&#xff1a; 搜索gzh【李桥桉】&#xff0c;需要win电脑安装包&#xff0c;回复【win-MS】。 搜索gzh【李桥桉】&#xff0c;需要mac电脑安装包&#xff0c;回复【mac-MS】。 注意&#xff1a;确保电脑为64位系统&#xff08;不是的话需要…

华为手环8相册表盘使用指南

随着科技的发展&#xff0c;智能手环已经成为越来越多人的选择。华为手环8作为一款备受好评的智能手环&#xff0c;不仅具备精准的监测功能&#xff0c;还拥有丰富的表盘样式。本文将向您介绍华为手环8如何使用相册表盘&#xff0c;通过这一功能&#xff0c;您可以轻松地将您的…

Windows 打开cmd/dos窗口的12种方式(全网最全)

文章目录 1. 从开始菜单的应用列表打开2. 从搜索打开3. 从运行打开4. 从文件资源管理器打开5. 从C:\Windows\System32\cmd.exe打开6. 从桌面>快捷方式打开&#xff08;需自己创建&#xff09;7. 从任务栏>快捷方式打开&#xff08;需自己创建&#xff09;8. 从开始菜单&g…

TV快应用系列——1.ExtScreen框架快速入门

系列文章目录 TV快应用系列——1.ExtScreen框架快速入门 ExtScreen框架快速入门 系列文章目录前言一、ExtScreen简介整体结构扩展屏和应用的区别 二、安装和环境配置1.安装编辑工具2.安装Vue开发环境1.1.1安装 Node1.1.2安装配置 npm下载安装npmnpm 设置淘宝镜像安装 vue-cli&…

图像分割的大变革:从SAM(分割一切)到FastSAM、MobileSAM

前言 SAM就是一类处理图像分割任务的通用模型。与以往只能处理某种特定类型图片的图像分割模型不同&#xff0c;SAM可以处理所有类型的图像。 在SAM出现前&#xff0c;基本上所有的图像分割模型都是专有模型。比如&#xff0c;在医学领域&#xff0c;有专门分割核磁图像的人工…

『DotNetBrowser』在.Net中的浏览器嵌入组件,该选择DotNetBrowser 还是 CefSharp?

&#x1f4e3;读完这篇文章里你能收获到 全方位对比DotNetBrowser 和 CefSharp的优缺点 文章目录 一、引言二、引擎三、架构1. CefSharp架构2. DotNetBrowser架构 四、对比1. 稳定性和内存使用2. 应用程序域3. AnyCPU4. H.264, AAC5. 安全6. Visual Studio设计器7. 嵌入应用程…

八、c++学习(加餐4:深入分析new和delete)

经过了两篇的类和对象分析&#xff0c;我们这一篇再次加餐&#xff0c;对new和malloc的分析&#xff0c;malloc的源码不在这篇介绍&#xff0c;会放到linux篇的内存池专题&#xff0c;所以我们这篇只要分析new。 这篇的主要目的就是&#xff0c;对象是怎么new出来的&#xff0…

技术干货——Selenium Python使用技巧(三)

目录 处理不同情况的等待 网页中的滚动操作 使用Selenium放大和缩小 查找元素的大小 获取元素的X和Y坐标 使用自定义配置文件禁用JavaScript 设置手动代理设置 总结&#xff1a; 处理不同情况的等待 在Selenium自动化测试中网页可能需要花费一些时间来加载&#xff0c;…

MybatisPlus从入门到精通-基础篇

文章目录 一、概述二、快速入门2.1 数据库准备2.2 创建springboot工程2.3 实体类准备2.4 测试MybatisPlus 三、MP常用配置3.1 设置表映射规则3.2 设置主键生成策略3.3 设置字段映射关系3.4 设置字段和列名的驼峰映射3.5 日志 四、基本使用4.1 增加&#xff08;插入&#xff09;…

TF卡/U盘扩容

1. 问题 在使用大于镜像、对TF卡/U盘烧录镜像以后&#xff0c;TF卡/U盘会出现一部分的空闲内存无法被使用&#xff0c;导致出现使用空间不足的报错&#xff0c;或运行大型项目不成功。 注意&#xff1a;本教程仅针对自行烧录镜像的用户&#xff0c;TF卡/U盘内如有出厂镜像则可…

【数据挖掘】时间序列教程【四】

3.3 划分变体 我们可以对上述 的主模型采用方差分析方法,并将中的总变异分解为 为残差平方和和可归因于各种频率的变化。 第二行是可能的,因为平方的所有交叉项都等于零,即对于所有 ,

基于JavaSwing的五子棋游戏设计

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/87987074?spm1001.2014.3001.5503 运行截图&#xff1a;

4.22. 卷积定理

1. 时域&#xff1a; 我们知道卷积运算是为了求系统的零状态响应的&#xff0c;即&#xff0c;如果输入给系统的信号是f(t)&#xff0c;系统函数是h(t)&#xff0c;那系统的输出是什么&#xff1f; 就是按照上述方式卷积得到 那上述的卷积在频率域是什么呢&#xff1f; 2. 卷积…

windows系统下的nvm环境安装

1、下载 https://github.com/coreybutler/nvm-windows/releases 直接下载zip包 并安装 2、安装 注意&#xff1a;尽量按照默认路径安装 否则可能出现 nvm 安装完成 后面下载使用node的时候有问题 3、安装完成检测 打开cmd命令 输入 nvm -v出现版本号 则安装成功 4、se…

FullGC调优100倍,掌握这3招,吊打JVM调优

前言&#xff1a; 在40岁老架构师尼恩的读者社区&#xff08;50&#xff09;中&#xff0c;很多小伙伴拿不到offer&#xff0c;或者拿不到好的offer。 尼恩经常给大家 优化项目&#xff0c;优化简历&#xff0c;挖掘技术亮点。 在指导简历的过程中&#xff0c; 线上问题排查…

【实用教程】教你一招 IDE 中比较骚的操作技巧!

我靠&#xff0c;这是个高手&#xff01;这真是个高手&#xff01; IDEA 有个很牛逼的功能&#xff0c;那就是后缀补全&#xff08;不是自动补全&#xff09;&#xff0c;很多人竟然不知道这个操作&#xff0c;还在手动敲代码。 这个功能可以使用代码补全来模板式地补全语句&…

02_04_02实时调度类_线程优先级代码实战

知识回忆 基础知识 Linux内核当中有3种调度策略: . SCHED_ OTHER分时调度策略;(普通进程) SCHED_ FIFO 实时调度策略,先到先服务; SCHED RR实时调度策略&#xff0c;时间片轮转。 备注:如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好&#xff0c;FI…

vim和vimplus安装详细步骤

1、vim安装 sudo apt update sudo apt install vim依次执行以上命令&#xff0c;安装好vim编辑器&#xff0c;安装好之后&#xff0c;直接使用vim hello.c进行测试&#xff0c;如果可以进入就没有问题。 2、vimplus安装 2.1 检查vim版本 vim --version vim --version | gre…

微信小程序入门教程

微信小程序入门教程 1、前言1. 相关介绍2. 开发工具 2、微信小程序注册3、 构建第一个微信小程序3.1 微信开发者工具3.1.1 小程序创建3.1.2 小程序项目结构目录介绍 3.2 Hbuilder 4、小程序的发布 1、前言 1. 相关介绍 要学习制作微信小程序&#xff0c;首先要先了解微信公众…