MyBatis-Plus 乐观锁

MyBatis-Plus 乐观锁详解

在现代应用中,乐观锁(Optimistic Locking)是解决并发问题的重要机制。它通过在数据更新时验证数据版本来确保数据的一致性,从而避免并发冲突。与悲观锁不同,乐观锁并不依赖数据库的锁机制,而是通过检查数据的版本或标志字段来判断数据是否被其他事务修改过。

MyBatis-Plus 提供了便捷的乐观锁支持,通过简单的配置即可实现乐观锁机制,在高并发场景下确保数据的一致性,同时不影响系统的并发性能。

一、什么是乐观锁

乐观锁是乐观并发控制的一种实现方式,它假设多个事务并发操作数据时不会产生冲突,或者认为冲突的概率较低,因此在每次操作时不会直接锁定资源。它的基本思路是在数据的每条记录中添加一个版本号字段,表示该数据的版本。当用户更新数据时,会检查该版本号是否发生变化。

乐观锁的典型工作流程如下:

  1. 在读取数据时,同时读取该记录的版本号。
  2. 在更新数据时,检查当前数据的版本号是否与读取时一致。
    • 如果版本号一致,则说明数据没有被其他事务修改,可以执行更新操作,并将版本号加 1。
    • 如果版本号不一致,则说明数据已经被其他事务修改,此时应当放弃更新,提示用户数据已被修改。

二、MyBatis-Plus 乐观锁的实现

MyBatis-Plus 中的乐观锁通过版本号字段来实现,通常需要以下几个步骤:

  1. 在实体类中为数据添加一个版本号字段。
  2. 配置 MyBatis-Plus 的乐观锁插件。
  3. 在更新时由 MyBatis-Plus 自动检查版本号,并在成功更新后递增版本号。

三、MyBatis-Plus 乐观锁的配置

1. 引入依赖

首先,需要在项目中引入 MyBatis-Plus 的依赖。如果已经使用 MyBatis-Plus,则可以跳过这一步。

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency>
2. 配置乐观锁插件

MyBatis-Plus 提供了内置的乐观锁插件,需要在项目的配置类中进行注册:

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

OptimisticLockerInnerInterceptor 是 MyBatis-Plus 提供的乐观锁插件,当我们进行更新操作时,它会自动检查数据的版本号,确保乐观锁生效。

3. 实体类配置

在实体类中,使用 @Version 注解标识乐观锁的版本字段。版本字段的类型通常为 IntegerLong,在更新数据时,MyBatis-Plus 会自动对该字段的值进行检查和递增。

@Data
public class User {private Long id;private String name;private Integer age;// 乐观锁版本号字段@Versionprivate Integer version;
}

在这个示例中,version 字段用于记录版本号,@Version 注解告诉 MyBatis-Plus 该字段是乐观锁的版本控制字段。

4. 更新操作

在执行更新操作时,MyBatis-Plus 会自动检查数据的版本号。如果版本号匹配,更新成功并将版本号加 1;如果版本号不匹配,则更新失败,防止数据被覆盖。

User user = userMapper.selectById(1L); // 读取用户数据
user.setName("New Name");
user.setAge(30);int result = userMapper.updateById(user);  // 执行更新if (result == 0) {// 如果返回值为 0,说明更新失败,版本号不匹配System.out.println("更新失败,数据可能已经被其他用户修改");
} else {// 更新成功,MyBatis-Plus 会自动将 version 字段加 1System.out.println("更新成功");
}

MyBatis-Plus 自动生成的更新 SQL 类似于以下 SQL:

UPDATE user
SET name = 'New Name', age = 30, version = version + 1
WHERE id = 1 AND version = 1;
  • version = 1 用于确保数据在更新时未被其他事务修改。
  • version = version + 1 在更新成功后,自动将版本号递增。

四、乐观锁的工作原理

MyBatis-Plus 的乐观锁通过 @Version 注解和乐观锁插件实现。当我们更新数据时,MyBatis-Plus 会在生成的 SQL 语句中加入对版本号的条件检查。如果该版本号匹配,更新成功,并将版本号加 1;如果版本号不匹配,说明数据已经被其他事务修改,更新操作会失败。

具体来说,MyBatis-Plus 的乐观锁会执行以下几个步骤:

  1. 查询数据:首先,用户读取数据,同时读取数据的版本号。
  2. 修改数据:用户修改数据内容,同时不修改版本号字段。
  3. 提交更新:当用户提交更新时,MyBatis-Plus 会在 WHERE 条件中加入版本号的检查。
    • 如果版本号匹配,更新成功,并将版本号加 1。
    • 如果版本号不匹配,更新失败,MyBatis-Plus 返回 0,表示更新未成功。

五、乐观锁失败处理

当使用乐观锁进行并发控制时,可能会出现更新失败的情况,通常是因为在用户提交修改前,数据已经被其他用户修改。这种情况下,需要根据业务场景进行处理,常见的处理方式包括:

  1. 提示用户重新获取最新数据:在更新失败后,提示用户数据已经发生变更,让用户重新查看并进行修改。
  2. 自动重试机制:在更新失败时,系统可以尝试重新读取最新数据,并在一定次数内重新执行更新操作。
  3. 合并数据:在某些情况下,可以尝试将用户的修改与数据库中的最新数据进行合并,避免数据丢失。

以下是自动重试机制的一个简单示例:

int retryCount = 3;  // 最大重试次数
boolean success = false;while (retryCount > 0 && !success) {User user = userMapper.selectById(1L);  // 重新读取数据user.setName("New Name");user.setAge(30);int result = userMapper.updateById(user);  // 尝试更新if (result == 0) {retryCount--;System.out.println("更新失败,剩余重试次数:" + retryCount);} else {success = true;System.out.println("更新成功");}
}if (!success) {System.out.println("更新失败,请重试");
}

在这个例子中,系统会在更新失败时自动重试,直到达到最大重试次数。

六、乐观锁的应用场景

乐观锁适合以下应用场景:

  1. 高并发环境:在高并发场景下,通过乐观锁可以减少数据库锁定的时间,提高系统的并发性能。特别是在读多写少的场景中,乐观锁可以很好地避免频繁的锁操作。
  2. 无状态服务:乐观锁适用于无状态服务,尤其是在分布式系统中。由于乐观锁不依赖数据库锁机制,因此适合分布式事务场景。
  3. 业务允许失败重试:在业务逻辑允许用户重试的情况下,乐观锁可以确保数据一致性,并提供简单的失败处理方式。

七、MyBatis-Plus 乐观锁的优缺点

优点:
  • 提高并发性能:乐观锁不需要数据库层面的锁定,避免了资源的长时间占用,适合高并发环境。
  • 避免死锁:由于乐观锁没有数据库的锁定操作,避免了在并发操作中发生死锁的问题。
  • 无侵入性:MyBatis-Plus 的乐观锁通过注解和插件实现,对现有代码的侵入性非常小。
缺点:
  • 更新失败可能性高:在并发写操作较多的场景下,乐观锁可能导致较高的更新失败率,需要增加重试机制来确保数据修改。
  • 适用场景有限:乐观锁更适合读多写少的业务场景,如果写操作频繁,可能会导致频繁的更新失败。

八、总结

MyBatis-Plus 的乐观锁

通过简单的配置和注解,可以轻松实现高并发场景下的数据并发控制。通过版本号机制,MyBatis-Plus 确保了在多用户同时操作数据时,数据不会被错误地覆盖。同时,乐观锁机制不依赖数据库的锁机制,适合无状态、分布式系统和高并发环境。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【有啥问啥】多臂老虎机(Multi-Armed Bandit,MAB)算法详解

多臂老虎机&#xff08;Multi-Armed Bandit&#xff0c;MAB&#xff09;算法详解 1. 引言 多臂老虎机&#xff08;Multi-Armed Bandit&#xff0c;MAB&#xff09;问题源自概率论和决策论&#xff0c;是一个经典的决策优化问题。最早提出的形式是赌场中的老虎机问题&#xff…

在线秘密基地--性能测试

根据之前的测试报告中的测试用例使用jmeter进行性能测试&#xff08;在性能测试之前&#xff0c;应先进行功能测试&#xff09;。 测试报告----功能测试_功能测试报告-CSDN博客https://blog.csdn.net/m0_74876421/article/details/141307905一、使用jmeter进行功能测试 可查看…

HDFS分布式文件系统01-HDFS架构与SHELL操作

HDFS分布式文件系统 学习目标第一课时知识点1-文件系统的分类单机文件系统网络文件系统分布式文件系统 知识点2-HDFS架构知识点3-HDFS的特点知识点4-HDFS的文件读写流程知识点5-HDFS的健壮性 第二课时知识点1-HDFS的Shell介绍HDFS Shell的语法格式如下。HDFS Shell客户端命令中…

STM32 软件触发ADC采集

0.91寸OLED屏幕大小的音频频谱&#xff0c;炫酷&#xff01; STM32另一个很少人知道的的功能——时钟监测 晶振与软件的关系&#xff08;深度理解&#xff09; STM32单片机一种另类的IO初始化方法 ADC是一个十分重要的功能&#xff0c;几乎任何一款单片机都会包含这个功能&a…

信息安全工程师(13)网络攻击一般过程

前言 网络攻击的一般过程是一个复杂且系统化的行为&#xff0c;其目标往往在于未经授权地访问、破坏或窃取目标系统的信息。 一、侦查与信息收集阶段 开放源情报收集&#xff1a;攻击者首先会通过搜索引擎、社交媒体、论坛等公开渠道获取目标的基本信息&#xff0c;如姓名、地址…

Pytest-如何将allure报告发布至公司内网

原理简介 使用Python启动HTTP服务器&#xff0c;指定一个端口号port&#xff0c;内网用户可以使用ipport访问报告。 本文章继续进阶&#xff0c;简单使用nginx进行一个代理&#xff0c;使用域名可以直接访问报告。 前情概述 Pytest-allure如何在测试完成后自动生成完整报告&am…

Axure大屏可视化模板:跨领域数据分析平台原型案例

随着信息技术的飞速发展&#xff0c;数据可视化已成为各行各业提升管理效率、优化决策过程的重要手段。Axure作为一款强大的原型设计工具&#xff0c;其大屏可视化模板在农业、园区、城市、企业数据可视化、医疗等多个领域得到了广泛应用。本文将通过几个具体案例&#xff0c;展…

生成PPT时支持上传本地的PPT模板了!

制作 PPT 时想要使用特定的 PPT 模板&#xff1f; 现在&#xff0c;歌者 PPT 的「自定义模板功能」已全面升级&#xff01;你可以轻松上传自己的本地 PPT 模板&#xff0c;无论是公司统一风格的模板&#xff0c;还是带有个人设计风格的模板&#xff0c;都能无缝导入歌者 PPT。…

什么是大数据?初学者快速入门手册

“大数据”这个词有点用词不当&#xff0c;因为它意味着预先存在的数据在某种程度上是小的&#xff08;事实并非如此&#xff09;&#xff0c;或者唯一的挑战是其庞大的规模&#xff08;规模是其中之一&#xff0c;但通常还有更多&#xff09;。简而言之&#xff0c;“大数据”…

预计2030年全球GO电工钢市场规模将达到120.6亿美元

GO电工钢&#xff0c;又称为冷轧取向电工钢。GO电工钢按重量计含硅量至少为0.6%&#xff0c;含碳量不超过0.08%&#xff0c;可含有不超过1.0%的铝&#xff0c;所含其他元素的比例并不使其具有其他合金钢的特性&#xff1b;厚度不超过0.56毫米&#xff1b;呈卷状的&#xff0c;则…

Mac端口扫描工具

文章目录 端口扫描工具域名/ip转换Lookupping功能端口扫描 端口扫描工具 Mac内置了一个网络工具 网络使用工具 按住 Command 空格 然后搜索 “网络实用工具” 或 “Network Utility” 即可 域名/ip转换Lookup ping功能 端口扫描 参考文献 端口扫描工具

小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(1)数字电路基础

目录 一、信号特征 二、组合逻辑电路和时序逻辑电路 1、组合逻辑电路 2、时序逻辑线路 三、信号转换 1、数字集成电路的分类 2、常用电平接口技术 四、可编程逻辑器件 flechazohttps://www.zhihu.com/people/jiu_sheng 小柴冲刺嵌入式系统设计师系列总目录https://blo…

使用 TypeScript 接口优化数据结构

在现代软件开发中&#xff0c;数据结构的设计至关重要&#xff0c;它直接影响到程序的性能和可维护性。TypeScript 作为一种静态类型的超集&#xff0c;为 JavaScript 带来了类型系统&#xff0c;使得开发者可以在编译时期就发现潜在的类型错误。本文将探讨如何利用 TypeScript…

uboot无法使用nfs下载文件的问题

一、系统环境 见这篇博客。 二、问题描述 uboot使用nfs下载文件出现 “T T T”&#xff0c;一直无法下载 三、解决方法 编辑/etc/nfs.conf文件&#xff1a; sudo xed /etc/nfs.conf开启udp: udpy之后重启nfs服务器&#xff1a; sudo /etc/init.d/nfs-kernel-server re…

使用GLib进行C语言编程的实例

本文将讨论使用GLib进行编程的基本步骤&#xff0c;GLib是一个跨平台的&#xff0c;用C语言编写的3个底层库(以前是5个)的集合&#xff0c;GLib提供了多种高级的数据结构&#xff0c;如内存块、双向和单向链表、哈希表等&#xff0c;GLib还实现了线程相关的函数、多线程编程以及…

知识库管理系统的未来趋势:从单一平台到生态系统

在数字化浪潮的推动下&#xff0c;知识库管理系统&#xff08;Knowledge Base Management System, KBMS&#xff09;正逐步从传统的单一平台向更加开放、灵活、智能的生态系统转变。这一转变不仅体现了技术进步的必然结果&#xff0c;也深刻反映了市场需求的变化。本文将分析随…

如何使用GLib的单向链表GSList

单向链表是一种基础的数据结构&#xff0c;也是一种简单而灵活的数据结构&#xff0c;本文讨论单向链表的基本概念及实现方法&#xff0c;并着重介绍使用GLib的GList实现单向链表的方法及步骤&#xff0c;本文给出了多个实际范例源代码&#xff0c;旨在帮助学习基于GLib编程的读…

基于飞腾平台的OpenCV的编译与安装

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

【LIO-SAM】LIO-SAM论文翻译(2020年)

【LIO】LIO-SAM论文翻译&#xff08;2020年&#xff09; 1&#xff0e;Abstract&#xff12;&#xff0e;INTRODUCTION&#xff14;&#xff0e;通过平滑和映射实现激光雷达惯性里程计A. 系统概述B. IMU Preintegration Factor&#xff08;推导过程参阅&#xff09;C. Lidar Od…

【我的 PWN 学习手札】fastbin reverse into tcache —— tcache key 绕过

目录 前言 一、tcache reverse into tcache 二、测试与模板 前言 之前提到过&#xff0c;较高版本的 glibc&#xff0c;设置了 key 对 tcachebin 内的 double free 进行了检查。 除了前面几篇手札罗列的绕过方法&#xff0c;今天又遇到一个&#xff0c;特此记录。之前利用…