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了,不能再减库存了,库存不能为负的。

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

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

相关文章

2023年全球软件开发大会(QCon北京站2023)9月:核心内容与学习收获(附大会核心PPT下载)

随着科技的飞速发展&#xff0c;全球软件开发大会&#xff08;QCon&#xff09;作为行业领先的技术盛会&#xff0c;为世界各地的专业人士提供了交流与学习的平台。本次大会汇集了全球的软件开发者、架构师、项目经理等&#xff0c;共同探讨软件开发的最新趋势、技术与实践。本…

提供多语种客户服务的正确方法:让你更接近全球客户

优质的客户支持是任何成功企业的核心。每位客户都希望得到全天候的及时响应。事实上&#xff0c;根据《哈佛商业评论》的研究报告&#xff0c;快速响应会促使人们在未来支付更多的费用。此外&#xff0c;在与全球客户打交道时&#xff0c;您的沟通必须超越语言障碍。用客户的语…

Java Chassis 3技术解密:注册中心分区隔离

原文链接&#xff1a;Java Chassis 3技术解密&#xff1a;注册中心分区隔离-云社区-华为云 注册中心负责实例的注册和发现&#xff0c;对微服务可靠运行起到举足轻重的作用。实例变更感知周期是注册中心最重要的技术指标之一。感知周期代表提供者的实例注册或者下线后&#xf…

Java后端sql编写

Java后端sql编写 注意事项二级目录三级目录 注意事项 在后端编写sql&#xff0c;不要直接编写sql语句进行查询 比如直接在service实现类中写下图这种语句 二级目录 三级目录

《如何制作类mnist的金融数据集》——1.数据集制作思路

1&#xff0e;数据集制作思路&#xff08;生成用于拟合金融趋势图像的分段线性函数&#xff09; 那么如何去制作这样的一个类minist的金融趋势曲线数据集呢&#xff1f; 还是如上图所示&#xff0c;为了使类别平均分布&#xff0c;因此可以选取三种“buy”的曲线、三种“sell”…

汽车研发测试大全

车研发中需要做的试验&#xff0c;这些试验都是保证我们的车能安全、稳定、可靠行驶的必要条件。主要包含以下内容&#xff1a; 一、整车试验项目 1.1整车可靠性试验 1.2 NVH试验 1.3 HVAC试验 1.4 EMC试验 1.5 化学分析试验 1.6 整车道路性能试验 二、零部件试验项目 …

什么是NTFS格式文件系统?Tuxera NTFS for Mac2024下载步骤

一般磁盘格式分为&#xff1a;FAT、FAT32、NTFS&#xff0c;这几种格式目前是我们最常遇到的文件系统格式&#xff0c;其中现在遇到最多的就是NTFS格式&#xff0c;为更好地了解这类文件系统格式&#xff0c;小编今天专门介绍一下什么是NTFS格式文件系统以及它的特点和局限性。…

git提交文本或者word到git教程,git创建仓库时候自带

简易的命令行入门教程: Git 全局设置: git config --global user.name “XX” git config --global user.email “XXXqq.com” 创建 git 仓库: mkdir test cd test git init touch README.md git add README.md git commit -m “first commit” git remote add origin https:…

eclipse ADT安装及abap cds模版创建

文章目录 1.前提2.安装3.创建cds模版 abap cds 常用语法 https://blog.csdn.net/weixin_49198221/article/details/135531478?spm1001.2014.3001.5501 1.前提 需要了解版本关系: **1.eclipse:**2023-06 (4.28), 2023-09 (4.29), 2023-12 (4.30) 2.Windows: ​ 1.Windows …

基本BGP配置试验 :配置 IBGP 和 EBGP

一、预习&#xff1a; BGP&#xff1a;Border Gateway Protocol 没有精妙的算法&#xff0c;但能承载大量的路由&#xff0c;它不生产路由&#xff0c;它是路由的搬运工 使用TCP做为传输层协议&#xff0c;端口号179&#xff0c;使用触发式路由更新 1. BGP路由…

LiveGBS流媒体平台GB/T28181功能-基础配置接入控制白名单黑名单配置控制设备安全接入设备单独配置接入密码

LiveGBS基础配置接入控制白名单黑名单配置控制设备安全接入设备单独配置接入密码 1、白名单配置应用场景2、接入控制2.1、白名单2.2、黑名单 3、搭建GB28181视频直播平台 1、白名单配置应用场景 LiveGBS国标流媒体服务&#xff0c;支持白名单配置。 可在设备注册前&#xff0…

SV-8004VP 网络对讲求助话筒,4个自定义按键

SV-8004VP网络对讲求助话筒&#xff0c;4个自定义按键 SV-8004VP是一款4按键求助对讲话筒&#xff0c;具有10/100M以太网接口&#xff0c;支持G.711音频编解码&#xff0c;其接收SIP网络的音频数据&#xff0c;实时解码播放&#xff0c;还配置了麦克风输入和扬声器输出。 SV-…

红日靶场2 指免杀360 个人学习记录

360安全卫士&#xff0c;有一说一&#xff0c;确实很强&#xff0c;这几天研究的MSF利用java反序列化的漏洞是无法利用的&#xff0c;其他方法也瘦小甚微 前几天在研究用 用免杀工具 go-shellcode-loader-main免杀工具对我们生成的木马进行加密 本来是用csa4.0黑客工具生成了…

中国互联网的早期形态

1 大约是从 1991 年开始&#xff0c;国内开始了第一个 BBS 站——北京长城站&#xff0c;经过长时间发展&#xff0c;直到 1995 年&#xff0c;随着计算机及其外设的大幅降价&#xff0c;BBS 才逐渐被部分人们所认识。少数玩 BBS 站的“极客”站长&#xff0c; 基于个人关系&am…

伪装目标检测模型论文阅读之:Zoom in and out

论文链接&#xff1a;https://arxiv.org/abs/2203.02688 代码;https://github.com/lartpang/zoomnet 1.摘要 最近提出的遮挡对象检测&#xff08;COD&#xff09;试图分割视觉上与其周围环境融合的对象&#xff0c;这在现实场景中是非常复杂和困难的。除了与它们的背景具有高…

第二证券:旅游股大涨 “预热”春节黄金周

在淄博烧烤热、哈尔滨冰雪热火爆出圈后&#xff0c;希望能接住文旅下一波“泼天富贵”的各地文旅局各出奇招并“卷”出新高度&#xff0c;被各地网友谈论“杀疯了”。 其间&#xff0c;A股游览概念股迎来一波集体上涨&#xff0c;成为不少出资者的重视热点&#xff0c;而行将到…

模拟日光AR汽车HUD的光学特性太阳光模拟器

AR HUD 的光学特性 几何光学可描述物体、透镜和成像之间的关系。将物体放在透镜及其焦点之间将会形成放大且离实际物体有一定距离的虚像[4]。这便是 HUD 生成虚像的方法。源物体&#xff08;在这里是散射屏或 TFT 面板&#xff09;在 HUD 反光镜光学系统的焦距内。这使相应虚像…

test0116测试

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

网络安全ctf比赛/学习资源整理,【解题工具、比赛时间、解题思路、实战靶场、学习路线】推荐收藏!

对于想学习或者参加CTF比赛的朋友来说&#xff0c;CTF工具、练习靶场必不可少&#xff0c;今天给大家分享自己收藏的CTF资源&#xff0c;希望能对各位有所帮助。 CTF在线工具 首先给大家推荐我自己常用的3个CTF在线工具网站&#xff0c;内容齐全&#xff0c;收藏备用。 1、C…

Androidmanifest文件加固和对抗

前言 恶意软件为了不让我们很容易反编译一个apk&#xff0c;会对androidmanifest文件进行魔改加固&#xff0c;本文探索androidmanifest加固的常见手法以及对抗方法。这里提供一个恶意样本的androidmanifest.xml文件&#xff0c;我们学完之后可以动手实践。 1、Androidmanife…