Mybatis Plus乐观锁实现

2024-08-27 23:44
文章标签 实现 mybatis plus 乐观

本文主要是介绍Mybatis Plus乐观锁实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 引言

乐观锁的主要作用在于提高系统的并发性能和减少锁冲突,同时保证数据的一致性。‌其原理简单来说就是,在修改数据的时候,判断数据是否被其他人改过,如果已被其他人改过,则修改失败。

2 代码

在SpringBoot 3.x+Mybatis Plus多数据源极简配置中的项目基础上更新代码,下面列出需要更新的代码。
在这里插入图片描述

2.1 org/example/mapper/InventoryMapperMaster.java

package org.example.mapper;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.example.entity.Inventory;@DS("master")
public interface InventoryMapperMaster extends BaseMapper<Inventory> {}

2.2 org/example/entity/Inventory.java

@Version就是乐观锁字段,用于判断数据是否被修改过。

package org.example.entity;import com.baomidou.mybatisplus.annotation.*;import java.util.Date;/** 库存* */
@TableName("t_inventory")
public class Inventory {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer quantity;@Version@TableField(fill = FieldFill.INSERT)private Integer version;@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getQuantity() {return quantity;}public void setQuantity(Integer quantity) {this.quantity = quantity;}public Integer getVersion() {return version;}public void setVersion(Integer version) {this.version = version;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}
}

2.3 org/example/controller/InventoryController.java

package org.example.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.example.entity.Inventory;
import org.example.entity.User;
import org.example.mapper.InventoryMapperMaster;
import org.example.mapper.UserMapperMaster;
import org.example.mapper.UserMapperSlave;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Controller
@RequestMapping("/InventoryController")
public class InventoryController {@Autowiredprivate InventoryMapperMaster inventoryMapperMaster;@RequestMapping(value = "/insert")@ResponseBody@Transactionalpublic Object insertMaster() {for (int i = 0; i < 5; i++) {Inventory inventory = new Inventory();inventory.setName("商品" + i);inventory.setQuantity(10);inventoryMapperMaster.insert(inventory);}return "数据插入成功";}@RequestMapping(value = "/update1")@ResponseBody@Transactionalpublic Object update1() {QueryWrapper<Inventory> q = new QueryWrapper<>();q.eq("name", "商品1");Inventory inventory = inventoryMapperMaster.selectOne(q);inventory.setQuantity(5);try {Thread.sleep(10000L);} catch (InterruptedException e) {throw new RuntimeException(e);}int i = inventoryMapperMaster.updateById(inventory);System.out.println("update1更新:" + i + "条");return "数据修改成功";}@RequestMapping(value = "/update2")@ResponseBody@Transactionalpublic Object update2() {QueryWrapper<Inventory> q = new QueryWrapper<>();q.eq("name", "商品1");Inventory inventory = inventoryMapperMaster.selectOne(q);inventory.setQuantity(0);int i = inventoryMapperMaster.updateById(inventory);System.out.println("update2更新:" + i + "条");return "数据修改成功";}}

2.4 org/example/conf/MyMetaObjectHandler.java

package org.example.conf;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;import java.util.Date;/*MyBatis-Plus 提供了一个便捷的自动填充功能,用于在插入或更新数据时自动填充某些字段,如创建时间、更新时间等*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.setFieldValByName("createTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);this.setFieldValByName("version", Integer.valueOf("0"), metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updateTime", new Date(), metaObject);}
}

2.5 org/example/conf/MybatisPlusConfig.java

package org.example.conf;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*MyBatis-Plus 配置*/
@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页拦截器interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁拦截器interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}}

3 测试

3.1 创建库存表

CREATE TABLE `t_inventory` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`name` varchar(30) DEFAULT NULL COMMENT '名称',`quantity` int(11) DEFAULT NULL COMMENT '数量',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`update_time` datetime DEFAULT NULL COMMENT '修改时间',`version` int(11) DEFAULT NULL COMMENT '版本',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3.2 新增数据

启动项目,然后打开浏览器访问:http://localhost:8080/InventoryController/insert,可以看到当前所有商品的库存数量都是10个。
在这里插入图片描述

3.3 修改数据

  1. 我们以“商品1”为例,先访问http://localhost:8080/InventoryController/update1,将“商品1”的数量改为5。然后立即(10秒内)访问:http://localhost:8080/InventoryController/update2,将“商品1”的数量改为0。为了模拟并发的情况,这里让update1休眠了10秒钟再提交。
    在这里插入图片描述
  2. 可以看到sql中自动加入了version=0的条件,这个version就是乐观锁,由系统自动维护,每次成功修改数据自动+1。具体流程是:
    2.1 update1 首先查询商品1,这时quantity=10,version=0,查完进入休眠。
    2.2 update2 在update1 休眠期间,将商品1的数量改为0,这时version自动+1,变成quantity=0,version=1。
    2.3 update1 休眠结束后提交更新,仍然按照version=0的条件更新数据,此时version=0的数据已经不存在了,因此可以看到update1更新了0条数据,避免了数据不一致的情况。
    在这里插入图片描述

5 完整代码

Gitee代码链接

这篇关于Mybatis Plus乐观锁实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1113122

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

Mybatis官方生成器的使用方式

《Mybatis官方生成器的使用方式》本文详细介绍了MyBatisGenerator(MBG)的使用方法,通过实际代码示例展示了如何配置Maven插件来自动化生成MyBatis项目所需的实体类、Map... 目录1. MyBATis Generator 简介2. MyBatis Generator 的功能3

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英