Mybatis-Plus:乐观锁与悲观锁

文章目录

  • 一、场景
  • 二、乐观锁与悲观锁
  • 三、模拟修改冲突
    • 3.1 数据库中增加商品表
    • 3.2 添加数据
    • 3.3 添加实体
    • 3.4 添加mapper
    • 3.5 测试
  • 四、乐观锁实现流程
    • 4.1 Mybatis-Plus实现乐观锁

一、场景

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小 李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太
高,可能会影响销量。又通知小王,你把商品价格降低30元。
此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王 也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据 库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就 完全被小王的覆盖了。
现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1 万多。

二、乐观锁与悲观锁

  • 上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过 了,则重新取出的被修改后的价格, 150元,这样他会将120元存入数据库。
  • 如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证 最终的价格是120元。

三、模拟修改冲突

3.1 数据库中增加商品表

CREATE TABLE t_product
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称 ',
price INT(11) DEFAULT 0 COMMENT '价格 ',
VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号 ',
PRIMARY KEY (id)
);

3.2 添加数据

INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人笔记本 ', 100);

3.3 添加实体

package com.qcby.mybatisplus.entity;
import lombok.Data;

@Data
public class Product {
	private Long id;
	private String name;
	private Integer price;
	private Integer version;
}

3.4 添加mapper

public interface ProductMapper extends BaseMapper<Product> {
}

3.5 测试

@Test
public void testConcurrentUpdate() {

	//1、小李
	Product p1 = productMapper.selectById(1L);
	System.out.println("小李取出的价格:" + p1.getPrice());
	
	//2、小王
	Product p2 = productMapper.selectById(1L);
	System.out.println("小王取出的价格:" + p2.getPrice());
	//3、小李将价格加了50元,存入了数据库
	p1.setPrice(p1.getPrice() + 50);
	int result1 = productMapper.updateById(p1);
	System.out.println("小李修改结果:" + result1);
	
	//4、小王将商品减了30元,存入了数据库
	p2.setPrice(p2.getPrice() - 30);
	int result2 = productMapper.updateById(p2);
	System.out.println("小王修改结果:" + result2);
	
	//最后的结果
	Product p3 = productMapper.selectById(1L);
	//价格覆盖,最后的结果:70
	System.out.println("最后的结果:" + p3.getPrice());
}

在这里插入图片描述

四、乐观锁实现流程

  • 数据库中添加version字段
  • 取出记录时,获取当前version
SELECT id,`name`,price,`version` FROM product WHERE id=1
  • 更新时, version + 1,如果where语句中的version版本不对,则更新失败
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1

4.1 Mybatis-Plus实现乐观锁

(1)修改实体类

@Data
public class Product {
	private Long id;
	private String name;
	private Integer price;
	@Version
	private Integer version;
}

(2)添加乐观锁插件配置
直接加到启动类中即可

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
	MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
	//添加乐观锁插件
	interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); 
	return interceptor;
}

(3)测试修改冲突

  • 小李查询商品信息:
    SELECT id,name,price,version FROM t_product WHERE id=?
  • 小王查询商品信息:
    SELECT id,name,price,version FROM t_product WHERE id=?
  • 小李修改商品价格,自动将version+1
    UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    Parameters: 外星人笔记本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
  • 小王修改商品价格,此时version已更新,条件不成立,修改失败
    UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    Parameters: 外星人笔记本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
  • 最终,小王修改失败,查询价格: 150
    SELECT id,name,price,version FROM t_product WHERE id=?
    (4)优化流程
    @Test
    public void testConcurrentVersionUpdate() {

        //小李取数据
        Product p1 = productMapper.selectById(1L);

        //小王取数据
        Product p2 = productMapper.selectById(1L);

        //小李修改 + 50
        p1.setPrice(p1.getPrice() + 50);
        int result1 = productMapper.updateById(p1);
        System.out.println("小李修改的结果:" + result1);

        //小王修改 - 30
        p2.setPrice(p2.getPrice() - 30);
        int result2 = productMapper.updateById(p2);
        System.out.println("小王修改的结果:" + result2);
        if(result2 == 0){
            //失败重试,重新获取version并更新
            p2 = productMapper.selectById(1L);
            p2.setPrice(p2.getPrice() - 30);
            result2 = productMapper.updateById(p2);
        }
        System.out.println("小王修改重试的结果:" + result2);

        //老板看价格
        Product p3 = productMapper.selectById(1L);
        System.out.println("老板看价格:" + p3.getPrice());
    }

在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 8.0在windows环境安装及配置

文章目录 一、下载二、安装三、配置环境变量 一、下载 1、先彻底卸载之前的MySQL&#xff0c;并清理其 残留文件 。 2、登录网址https://www.mysql.com/ 3、点击网址左下角“中文”按钮&#xff0c;切换到中文界面 4、点击网页上方的“下载”按钮&#xff0c;然后点击网…

Python 实现 NLP 的完整流程

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

redux 结合 @reduxjs/toolkit 的使用

1&#xff0c;使用步骤 使用React Toolkit 创建 counterStore&#xff08;store目录下&#xff09; --> 为React注入store&#xff08;src下面的index&#xff09; --> React组件使用store中的数据&#xff08;组件&#xff09; 2&#xff0c;例如下面有一个简单加减的…

GDC杂感:怎么提高游戏销量?

1、2018年的一个独立游戏制作人在GDC分享了其教训总结&#xff0c;得奖但销量不佳&#xff0c; 大意是&#xff1a;画面&#xff0c;辨识度的重要性&#xff0c;平庸的游戏容易扑街&#xff1b; 直播对不同类型的作用不同&#xff0c;差别能达到几十倍。 游戏品质与销量并不…

【Kotlin】上手学习之类型篇

一、类型 1.1 基本类型 主要分为 数字及其无符号版布尔字符字符串数组 1.1.1 数字 整数类型 Kotlin 提供了一组表示数字的内置类型。 对于整数&#xff0c;有四种不同大小的类型&#xff0c;因此值的范围也不同&#xff1a; 类型大小&#xff08;比特数&#xff09;最小…

迅为RK3576开发板Android 多屏显示

迅为iTOP-3576开发板采用瑞芯微RK3576高性能、低功耗的应用处理芯片&#xff0c;集成了4个Cortex-A72和4个Cortex-A53核心&#xff0c;以及独立的NEON协处理器。它适用于ARM PC、边缘计算、个人移动互联网设备及其他多媒体产品。 1.1 Android 多屏同显 iTOP-RK3576 开发板支持…

解决关于Xcode16提交审核报错

# 问题描述 The following issues occurred while distributing your application. Asset validation failed Invalid Executable. The executable xxx.app/Frameworks/HappyDNS.framework/HappyDNS contains bitcode.(lD:ef5dd249-731f-4731-8173-8e4a12519352) Asset valida…

语义检索效果差?深度学习rerank VS 统计rerank选哪个

前段时间我开发了一个用白话文搜索语义相近的古诗词的应用&#xff08;详见&#xff1a;《朋友圈装腔指南&#xff1a;如何用向量数据库把大白话变成古诗词》&#xff09;&#xff0c;但是有时候搜索结果却不让人满意&#xff0c;排名靠前的结果和查询的语义没啥关系&#xff0…

Linux 常用命令 - chmod 【改变文件或目录权限】

简介 “chmod” 这个命令来自于 “change mode” 的缩写&#xff0c;用于更改文件或目录的访问权限。这个命令允许用户设定谁可以读取、写入或执行一个文件。在 Linux 和其他类 Unix 系统中&#xff0c;文件权限对系统安全和用户隐私至关重要。 Linux/Unix 的文件调用权限分为…

基于机器学习的电信用户流失预测与数据分析可视化

完整源码项目包获取→点击文章末尾名片&#xff01; 背景描述 根据IBM商业社区分享团队描述&#xff0c;该数据集为某电信公司在加利福尼亚为7000余位用户&#xff08;个人/家庭&#xff09;提供电话和互联网服务的相关记录。描述用户基本情况&#xff0c;包括每位用户已注册的…

【Sql递归查询】Mysql、Oracle、SQL Server、PostgreSQL 实现递归查询的区别与案例(详解)

文章目录 Mysql 5.7 递归查询Mysql 8 实现递归查询Oracle递归示例SQL Server 递归查询示例PostgreSQL 递归查询示例 更多相关内容可查看 Mysql 5.7 递归查询 MySQL 5.7 本身不直接支持标准 SQL 中的递归查询语法&#xff08;如 WITH RECURSIVE 这种常见的递归查询方式&#xf…

接上篇基于Alertmanager 配置钉钉告警

Alertmanager 是一个用于处理和管理 Prometheus 警报的开源工具。它负责接收来自 Prometheus 服务器的警报&#xff0c;进行去重、分组、静默、抑制等操作&#xff0c;并通过电子邮件、PagerDuty、Slack 等多种渠道发送通知。 主要功能 去重&#xff1a;合并相同或相似的警报&…

Qt应用之MDI(多文档设计)

qt creator 版本6.8.0 MinGW 64bit 由此模块可以扩展成设计一个qt文本编辑器。 界面如下 部分功能展示如下 新建文件 打开文件 mdi模式、级联模式和平铺模式 界面和程序构建过程。 1.如图所需.cpp和.h文件 2.mainwindow.ui和tformdoc.ui界面布局如下 不懂什么是Action如何…

软件授权管理中的软件激活向导示例

软件激活向导示例 在软件许可中&#xff0c;提供许可应该是简单和安全的。这适用于想要在中央许可证服务器上创建新许可证的软件开发人员&#xff0c;也适用于需要在其设备上获得许可证的最终用户。如果所讨论的系统有互联网连接&#xff0c;或是暂时的连接&#xff0c;就可以…

GB44495-2024 汽车整车信息安全技术要求 - V2X部分前置要求

背景 GB 44495-2024《汽车整车信息安全技术要求》中关于V2X&#xff08;车与外界通信&#xff09;的部分&#xff0c;主要关注于通信安全要求&#xff0c;旨在确保车辆在与外部设备进行数据交互时的信息安全。其测试大致可分为消息层&#xff08;数据无异常&#xff09;、应用…

phpstudy靶场搭建问题

前言&#xff1a; 靶场搭建遇到的问题&#xff0c;记录一下&#xff0c;可能是基础不牢吧&#xff0c;老是遇到奇奇怪怪的问题 思路&#xff1a; 跟着网上的搭建走一遍 内容&#xff1a; 目录 搭建pikachu遇到的问题 搭建pikachu遇到的问题 其实并不是第一次搭建&#x…

【Excel】【VBA】双列排序:坐标从Y从大到小排列之后相同Y坐标的行再对X从小到大排列

Excel VBA 双列排序 功能概述 这段VBA代码实现了Excel中的双列排序功能&#xff0c;具体是&#xff1a; 跳过前3行表头先按C列数据从大到小排序在C列值相同的情况下&#xff0c;按B列从大到小排序排序时保持整行数据的完整性 流程图 #mermaid-svg-XJERemQluZlM4K8l {font-fa…

Hive SQL必刷练习题:留存率问题

首次登录算作当天新增&#xff0c;第二天也登录了算作一日留存。可以理解为&#xff0c;在10月1号登陆了。在10月2号也登陆了&#xff0c;那这个人就可以算是在1号留存 今日留存率 &#xff08;今日登录且明天也登录的用户数&#xff09; / 今日登录的总用户数 * 100% 解决思…

C++基础入门(二)

目录 前言 一、重载 1.函数重载 2.运算符重载 二、构造函数 1.什么是构造函数 2.带参数的构造函数 3.使用初始化列表 4.this关键字 5.new关键字 三、析构函数 1.什么是析构函数 四、静态成员变量 1.静态成员的定义 2.静态成员变量的作用 五、继承 1.继承基本概…

Redis 中 TTL 的基本知识与禁用缓存键的实现策略(Java)

目录 前言1. 基本知识2. Java代码 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 单纯学习Redis可以看我前言的Java基本知识路线&#xff01;&#xff01; 对于Java的基本知识推荐阅读&#xff1a; java框架…