当前位置: 首页 > news >正文

spring boot学习第八篇:通过spring boot、jedis实现秒单

参考:Redis实现分布式锁的7种方案 - 知乎

1、 准备数据库表,如下SQL表示库存表,有主键ID和库存数量字段

CREATE TABLE `t_stock` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`quantity` bigint(20) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

初始数据id           quantity

              1111       9

2、pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.4</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.hmblogs</groupId><artifactId>hmblogs</artifactId><version>0.0.1-SNAPSHOT</version><name>hmblogs</name><description>hmblogs</description><properties><java.version>8</java.version><druid.version>1.2.8</druid.version><log4jdbc.version>1.16</log4jdbc.version></properties><dependencies><!-- druid数据源驱动 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- mybatis --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--Mysql依赖包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--lombok插件--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--监控sql日志--><dependency><groupId>org.bgee.log4jdbc-log4j2</groupId><artifactId>log4jdbc-log4j2-jdbc4.1</artifactId><version>${log4jdbc.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.9</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

3、应用配置文件

server:port: 8081servlet.context-path: /#配置数据源
spring:datasource:druid:db-type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpyurl: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:eladmin}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=falseusername: ${DB_USER:root}password: ${DB_PWD:123456}

4、StockMapper.xml如下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hmblogs.backend.dao.StockMapper"><resultMap id="BaseResultMap" type="com.hmblogs.backend.entity.Stock"><id column="id" property="id"/><result column="quantity" property="quantity"/></resultMap><sql id="BaseResultMap">id, quantity</sql><select id="findAll" resultMap="BaseResultMap">select<include refid="BaseResultMap"/>from t_stock</select><select id="findById" resultMap="BaseResultMap"  parameterType="com.hmblogs.backend.entity.Stock">select<include refid="BaseResultMap"/>from t_stockwhere id=#{id}</select><update id="updateStockById" parameterType="com.hmblogs.backend.entity.Stock">update t_stock set quantity=quantity-1 where id=#{id}</update>
</mapper>

5、BackendApplication

package com.hmblogs.backend;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class BackendApplication {public static void main(String[] args) {SpringApplication.run(BackendApplication.class, args);}}

6、Stock.java如下

package com.hmblogs.backend.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@Data
@TableName("t_stock")
public class Stock {@TableId(value="id", type = IdType.AUTO)private Integer id;private Integer quantity;}

7、StockMapper

package com.hmblogs.backend.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hmblogs.backend.entity.Stock;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface StockMapper extends BaseMapper<Stock> {List<Stock> findAll();Stock findById(Stock stock);Integer updateStockById(Stock stock);
}

8、OrderController

package com.hmblogs.backend.controller;import com.hmblogs.backend.dao.StockMapper;
import com.hmblogs.backend.entity.Stock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;@RestController
@Slf4j
public class OrderController {@Autowiredprivate StockMapper stockMapper;//总库存private long nKuCuen = 0;//商品key名字private String shangpingKey = "computer_key";//获取锁的超时时间 秒private int timeout = 30 * 1000;@GetMapping("/qiangdan")public List<String> qiangdan() {//抢到商品的用户List<String> shopUsers = new ArrayList<>();//构造很多用户List<String> users = new ArrayList<>();IntStream.range(0, 10000).parallel().forEach(b -> {users.add("神牛-" + b);});//初始化库存nKuCuen = 10;//模拟开抢users.parallelStream().forEach(b -> {String shopUser = qiang(b);if (!StringUtils.isEmpty(shopUser)) {shopUsers.add(shopUser);}});return shopUsers;}/*** 模拟抢单动作** @param b* @return*/private String qiang(String b) {//用户开抢时间long startTime = System.currentTimeMillis();//未抢到的情况下,30秒内继续获取锁while ((startTime + timeout) >= System.currentTimeMillis()) {//商品是否剩余if (nKuCuen <= 0) {break;}Jedis jedisCom = new Jedis("localhost",6379);jedisCom.auth("heming");if (jedisCom.setnx(shangpingKey, b)==1) {//用户b拿到锁log.info("用户{}拿到锁...", b);try {//商品是否剩余if (nKuCuen <= 0) {break;}//模拟生成订单耗时操作,方便查看:神牛-50 多次获取锁记录try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}//抢购成功,商品递减,记录用户nKuCuen -= 1;int id = 1111;Stock stock = new Stock();stock.setId(id);Stock stockDo = stockMapper.findById(stock);Integer quantity = stockDo.getQuantity();if(quantity!=null && quantity>0){stockMapper.updateStockById(stock);log.info("update success.");}else{log.info("no update.");}//抢单成功跳出log.info("用户{}抢单成功跳出...所剩库存:{}", b, nKuCuen);return b + "抢单成功,所剩库存:" + nKuCuen;} finally {log.info("用户{}释放锁...", b);//释放锁jedisCom.del(shangpingKey, b);}}}return "";}}

9、验证

浏览器访问http://localhost:8081/qiangdan

查看Idea的console内容,

 将console内容拿到notepad++里面搜索

但是,搜索"update success."内容,预期是9次,实际也是9次,符合我的需要,没有让库存变成负数,

 查看数据库表的库存,id为1111的记录的quantity为0,不是1,也不是负数

10、继续第二种纬度的验证 

StockController的代码如下:

package com.hmblogs.backend.controller;import com.hmblogs.backend.dao.StockMapper;
import com.hmblogs.backend.entity.Stock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;
import java.util.Date;@RestController
@Slf4j
public class StockController {@Autowiredprivate StockMapper stockMapper;/*** redis test* @return*/@GetMapping(value = "/reduceStock")public void redisTestLock(){log.info("reduceStock");int id = 1111;String key = "reduceStock"+id;String time = new Date().getTime()+"";Jedis jedisCom = new Jedis("localhost",6379);jedisCom.auth("heming");if (jedisCom.setnx(key, time)==1) {log.info("{}生成锁...", time);try{Stock stock = new Stock();stock.setId(id);Stock stockDo = stockMapper.findById(stock);Integer quantity = stockDo.getQuantity();if(quantity!=null && quantity>0){stockMapper.updateStockById(stock);log.info("update success.");}else{log.info("no update.");}} finally {log.info("{}释放锁...", time);//释放锁jedisCom.del(key, time);}}}
}

将库存改为10,验证,通过压测验证有没有保证锁应该有的作用,控制查库存和当不小于0的时候减少库存这2个逻辑的原子性,预期做到,实际做到了。利用APIPost工具做压测,如下图所示

查看server的控制台

 

 然后把这些内容复制到notepad++里面搜索,

搜索reduceStock,有100个结果

搜索"生成锁..."和"释放锁...",都有14次结果,说明jedisCom.setnx(key, time)==1成立的次数有14次。

 搜索"update success.",有10次结果,说明减少库存减少了10次,

此时查看数据库表的库存,发现为0

 搜索"no update.",发现有4个结果,说明有4次获得锁了,但是库存已经是0了,不能再减库存了,库存不能为负的。

相关文章:

spring boot学习第八篇:通过spring boot、jedis实现秒单

参考&#xff1a;Redis实现分布式锁的7种方案 - 知乎 1、 准备数据库表&#xff0c;如下SQL表示库存表&#xff0c;有主键ID和库存数量字段 CREATE TABLE t_stock (id bigint(20) NOT NULL AUTO_INCREMENT,quantity bigint(20) NOT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEF…...

NineAi 新版AI系统网站源码 ChatGPT

简介: Nine AI.ChatGPT是基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,真正像人类一样来聊天交流,甚至能完成撰写邮件、视频脚本、文案、翻译、代码,写论文等任务。 NineAi 新版A…...

开源监控服务一瞥:Prometheus、Grafana、Zabbix、Nagios、Icinga和Open-Falcon

前言 随着信息技术的发展&#xff0c;监控服务在维护系统稳定性和性能方面变得越来越重要。本文将比较一些流行的开源监控服务&#xff0c;以帮助你选择适合你需求的解决方案。 监控服务对比 监控服务特点优势不足性能扩展性安全性Prometheus- 多维度数据模型- 监控容器化环…...

使用WAF防御网络上的隐蔽威胁之扫描器

在网络安全领域&#xff0c;扫描器是用于侦察和识别网络系统漏洞的工具。 它们可以帮助网络管理员识别安全漏洞&#xff0c;也可能被攻击者用来寻找攻击目标。 扫描器的基本概念 定义&#xff1a;扫描器是一种自动化工具&#xff0c;用于探测网络和服务器中的漏洞、开放端口、…...

企业信息安全管理制度

随着信息化程度的日益推进&#xff0c;企业信息的脆弱性也日益暴露。如何规范日趋复杂的信息安全保障体系建设&#xff0c;如何进行信息风险评估保护企业的信息资产不受侵害&#xff0c;已成为当前行业实现信息化运作亟待解决的问题。 一、企业的信息及其安全隐患 在我公司&am…...

Qt中的线程池

Qt中的线程池 目录 1 为什么需要线程池 2 Qt中有哪些方式实现线程池 3 如何通过QThreadPool类实现线程池 4 如何通过QtConcurrent库实现线程池 5 如何通过自定义的方式实现线程池 5 小结 1 为什么需要线程池 线程池是多线程编程中常用的一种技术&#xff0c;可以帮助管理系统中…...

使用Spring Boot集成中间件:Elasticsearch基础->提高篇

使用Spring Boot集成中间件&#xff1a;Elasticsearch基础->提高篇 导言 Elasticsearch是一个开源的分布式搜索和分析引擎&#xff0c;广泛用于构建实时的搜索和分析应用。在本篇博客中&#xff0c;我们将深入讲解如何使用Spring Boot集成Elasticsearch&#xff0c;实现数…...

【Docker】Dockerfile构建最小镜像

&#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Docker的相关操作吧 目录 &#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 前言 一.Dockerfile是什么 二.Dock…...

【严重】GitLab 以其他用户身份执行 Slack 命令

漏洞描述 GitLab 是由GitLab公司开发的、基于Git的集成软件开发平台。使用 Slack 命令在 Slack 聊天环境中运行常见的 GitLab 操作。 GitLab 受影响版本中&#xff0c;由于配置Slack/Mattermost 集成时&#xff0c;未正确验证用户身份信息&#xff0c;导致攻击者可以使用其他…...

【卡梅德生物】纳米抗体文库构建

纳米抗体文库构建服务是一项提供定制化纳米抗体文库的服务&#xff0c;旨在满足研究者和生物制药公司对高质量抗体的需求。这项服务通常包括以下主要步骤&#xff1a; 1.抗原设计和制备&#xff1a; -客户提供目标抗原信息&#xff0c;或由服务提供商协助设计抗原。 -抗原制…...

MySQL修炼手册6:子查询入门:在查询中嵌套查询

目录 写在开头1 子查询基础概念1.1 了解子查询的基本概念1.2 子查询与主查询的关系 2 标量子查询详细展开2.1 学会使用标量子查询2.1.1 在SELECT语句中使用2.1.2 在WHERE子句中使用2.1.3 在ORDER BY子句中使用 2.2 标量子查询在条件判断中的应用2.2.1 使用比较运算符2.2.2 使用…...

01章【JAVA开发入门】

计算机基本概念 计算机组成原理 计算机组装 计算机&#xff1a;电子计算机&#xff0c;俗称电脑。是一种能够按照程序运行&#xff0c;自动、高速处理海量数据的现代化智能电子设备。由硬件和软件所组成&#xff0c;没有安装任何软件的计算机称为裸机。常见的形式有台式计算机、…...

ARM day1

一、概念 ARM可以工作的七种模式用户、系统、快中断、中断、管理、终止、未定义ARM核的寄存器个数 37个32位长的寄存器&#xff0c;当前处理器的模式决定着哪组寄存器可操作&#xff0c;且任何模式都可以存取&#xff1a; PC(program counter程序计数器) CPSR(current program…...

ImageNet Classification with Deep Convolutional 论文笔记

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…...

Spring Boot中加@Async和不加@Async有什么区别?设置核心线程数、设置最大线程数、设置队列容量是什么意思?直接在yml中配置线程池

在 Spring 中&#xff0c;Async 注解用于将方法标记为异步执行的方法。当使用 Async 注解时&#xff0c;该方法将在单独的线程中执行&#xff0c;而不会阻塞当前线程。这使得方法可以在后台执行&#xff0c;而不会影响主线程的执行。 在您提供的代码示例中&#xff0c;a1() 和…...

自动化理论基础(2)—开发语言之Python

一、知识汇总 掌握 Python 编程语言需要具备一定的基础知识和技能&#xff0c;特别是对于从事自动化测试等领域的工程师。以下是掌握 Python 的一些关键方面&#xff1a; 基本语法&#xff1a; 理解 Python 的基本语法&#xff0c;包括变量、数据类型、运算符、条件语句、循环…...

Spark算子(RDD)超细致讲解

SPARK算子&#xff08;RDD&#xff09;超细致讲解 map,flatmap,sortBykey, reduceBykey,groupBykey,Mapvalues,filter,distinct,sortBy,groupBy共10个转换算子 &#xff08;一&#xff09;转换算子 1、map from pyspark import SparkContext# 创建SparkContext对象 sc Spark…...

转盘寿司(100%用例)C卷 (JavaPythonC++Node.jsC语言)

寿司店周年庆,正在举办优惠活动回馈新老客户。 寿司转盘上总共有n盘寿司,prices[i]是第i盘寿司的价格,如果客户选择了第i盘寿司,寿司店免费赠送客户距离,第i盘寿司最近的下一盘寿司i,前提是prices[j]< prices[i],如果没有满足条件的j,则不赠送寿司。 每个价格的寿司都…...

【python】搭配Miniconda使用VSCode

现在的spyder总是运行出错&#xff0c;启动不了&#xff0c;尝试使用VSCode。 一、在VSCode中使用Miniconda管理的Python环境&#xff0c;可以按照以下步骤进行&#xff1a; a. 确保Miniconda环境已经安装并且正确配置。 b. 打开VSCode&#xff0c;安装Python扩展。 打开VS…...

从购买服务器到部署前端VUE项目

购买 选择阿里云服务器&#xff0c;地址&#xff1a;https://ecs.console.aliyun.com/home。学生会送一个300的满减券&#xff0c;我买了一个400多一年的&#xff0c;用券之后100多点。 使用SSH连接服务器 我选择的是vscode 中SSH工具。 安装一个插件 找到配置文件配置一下…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...