MyBatisPlus乐观锁和悲观锁的实现示例

 更新时间:2025年11月30日 15:01:08   作者:222you  
本文主要介绍了MyBatisPlus乐观锁和悲观锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1.场景

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小 李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。

此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王  也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据  库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就 完全被小王的覆盖了。

现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1 万多。

2.乐观锁和悲观锁

上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过 了,则重新取出的被修改后的价格,  150元,这样他会将120元存入数据库。

如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证 最终的价格是120元。

3.乐观锁实现

添加插件:

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        // 添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

创建表:

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)
);

添加数据:

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

如图:

编写实体类:

package com.qcby.entity;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

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

    @Version
    private Integer version;
}

mapper:

package com.qcby.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qcby.entity.Product;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductMapper extends BaseMapper<Product> {
}

测试:

package com.qcby;

import com.qcby.entity.Product;
import com.qcby.mapper.ProductMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MybatisTestOptimisticLock {

    @Autowired
    private ProductMapper productMapper;

    @Test
    public void testOptimisticLock() {
        // 小李查询商品信息
        Product productLi = productMapper.selectById(1L);
        System.out.println("小李查询价格: " + productLi.getPrice() + ", 版本: " + productLi.getVersion());

        // 小王查询商品信息
        Product productWang = productMapper.selectById(1L);
        System.out.println("小王查询价格: " + productWang.getPrice() + ", 版本: " + productWang.getVersion());

        // 小李修改价格 +50
        productLi.setPrice(productLi.getPrice() + 50);
        int resultLi = productMapper.updateById(productLi);
        System.out.println("小李修改结果: " + resultLi);

        if (resultLi > 0) {
            Product afterLi = productMapper.selectById(1L);
            System.out.println("小李修改后价格: " + afterLi.getPrice() + ", 版本: " + afterLi.getVersion());
        }

        // 小王修改价格 -30
        productWang.setPrice(productWang.getPrice() - 30);
        int resultWang = productMapper.updateById(productWang);
        System.out.println("小王修改结果: " + resultWang);

        if (resultWang == 0) {
            // 小王修改失败,需要重新尝试
            System.out.println("小王修改失败,版本已变更,需要重新操作");
            Product newProductWang = productMapper.selectById(1L);
            newProductWang.setPrice(newProductWang.getPrice() - 30);
            resultWang = productMapper.updateById(newProductWang);
            System.out.println("小王重试结果: " + resultWang);
        }

        // 最终价格
        Product finalProduct = productMapper.selectById(1L);
        System.out.println("最终价格: " + finalProduct.getPrice() + ", 版本: " + finalProduct.getVersion());
    }
}

实际流程:

1. 小李查询: SELECT id,name,price,version FROM t_product WHERE id=1
   结果: price=100, version=0

2. 小王查询: SELECT id,name,price,version FROM t_product WHERE id=1
   结果: price=100, version=0

3. 小李更新: UPDATE t_product SET name=?, price=150, version=1
           WHERE id=1 AND version=0
   成功: version变为1

4. 小王更新: UPDATE t_product SET name=?, price=70, version=1
           WHERE id=1 AND version=0
   失败: version条件不匹配

5. 小王重试: 重新查询 price=150, version=1
           更新: SET price=120, version=2 WHERE id=1 AND version=1
   成功

6. 最终价格: 120元 (正确的价格)

4.悲观锁

悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程

到此这篇关于MyBatisPlus乐观锁和悲观锁的实现示例的文章就介绍到这了,更多相关MyBatisPlus乐观锁和悲观锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • spring boot的maven配置依赖详解

    spring boot的maven配置依赖详解

    本篇文章主要介绍了spring boot的maven配置依赖详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Spring之关于PropertyDescriptor的扩展剖析

    Spring之关于PropertyDescriptor的扩展剖析

    这篇文章主要介绍了Spring之关于PropertyDescriptor的扩展剖析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • SpringBoot实现缓存预热的几种常用方案

    SpringBoot实现缓存预热的几种常用方案

    缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制,本文给大家介绍了SpringBoot实现缓存预热的几种常用方案,并通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-02-02
  • Spring中的@EnableScheduling定时任务注解

    Spring中的@EnableScheduling定时任务注解

    这篇文章主要介绍了Spring中的@EnableScheduling注解,@EnableScheduling是 Spring Framework 提供的一个注解,用于启用 Spring 的定时任务功能,通过使用这个注解,可以在 Spring 应用程序中创建定时任务,需要的朋友可以参考下
    2024-01-01
  • 解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

    解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

    本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常问题,通过排查和总结,作者发现使用MyBatis-Plus Boot Starter可以解决这个问题,文章详细对比了MyBatis-Plus Boot Starter和MyBatis Spring Boot Starter的功能和使用场景
    2025-01-01
  • Java动态规划之编辑距离问题示例代码

    Java动态规划之编辑距离问题示例代码

    这篇文章主要介绍了Java动态规划之编辑距离问题示例代码,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • 通过自定制LogManager实现程序完全自定义的logger

    通过自定制LogManager实现程序完全自定义的logger

    本章主要阐述怎么完全定制化LogManager来实现应用程序完全自定制的logger,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • SpringBoot集成Mybatis的实现步骤

    SpringBoot集成Mybatis的实现步骤

    这篇文章主要介绍了SpringBoot集成Mybatis的实现步骤,本文通过SpringBoot +MyBatis 实现对数据库学生表的查询操作,需要的朋友可以参考下
    2020-12-12
  • 基于JavaMail的Java实现简单邮件发送功能

    基于JavaMail的Java实现简单邮件发送功能

    这篇文章主要为大家详细介绍了基于JavaMail的Java实现简单邮件发送功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • 基于java开发之系统托盘的应用

    基于java开发之系统托盘的应用

    本篇文章介绍了,基于java开发之系统托盘的应用。需要的朋友参考下
    2013-05-05

最新评论