MySQL乐观锁

news2024/11/29 23:45:44

前言

乐观锁是一种并发控制机制,它假设在大多数情况下不会发生冲突,因此在事务执行过程中不加锁。只有在提交时才会检查数据是否被其他事务修改过。如果数据在此期间被修改了,则当前事务会被回滚或者需要重新执行。乐观锁的主要用途和优势包括:

  1. 提高读取性能:由于乐观锁不会锁定资源,因此在读取数据时没有阻塞,可以极大地提高读取操作的性能,特别适合读多写少的应用场景。

  2. 减少死锁的可能性:因为乐观锁不使用实际的数据库锁,所以避免了传统悲观锁可能导致的死锁问题。

  3. 简化代码实现:乐观锁的实现通常比悲观锁简单,特别是在分布式系统中,因为它不需要复杂的锁管理逻辑。

  4. 支持高并发场景:在许多用户同时访问相同数据的情况下,乐观锁能够更好地处理并发请求,减少了等待时间,提高了系统的吞吐量。

  5. 用户体验改善:在Web应用等环境中,乐观锁可以减少用户界面的等待时间,提供更流畅的用户体验。

  6. 适用于长事务:对于那些涉及长时间运行的业务逻辑,采用乐观锁可以避免长时间持有锁导致的资源浪费。

  7. 支持离线或异步更新:乐观锁允许客户端在离线状态下进行数据修改,并在上线后合并这些更改,这在移动应用开发中尤其有用。

适用场景

  • 读多写少:当系统中读取操作远多于写入操作时。
  • 低冲突率:当数据项被多个事务同时修改的概率较低时。
  • 分布式系统:在分布式系统中,乐观锁可以简化跨节点的数据一致性问题。
  • 对最终一致性要求不高:如果应用程序可以接受短时间内的数据不一致,直到下一个成功的更新操作完成。

注意事项

  • 高冲突率下的效率降低:如果数据项频繁地被多个事务修改,乐观锁会导致大量重试,影响性能。
  • 版本号或时间戳的维护:需要正确设计和维护用于检测冲突的版本号或时间戳字段。
  • 业务逻辑复杂性增加:虽然乐观锁简化了某些方面,但处理冲突和重试逻辑可能会增加业务逻辑的复杂度。

1. 什么是乐观锁

乐观锁通常通过版本号(Version Number)时间戳(Timestamp)来实现。当一个记录被读取时,会同时获取它的版本号或时间戳。在更新这条记录之前,会再次检查这个版本号或时间戳,确保自上次读取以来没有被修改。如果有修改,那么更新操作将失败,应用程序可以根据具体需求选择重试或者其他处理方式。

1.1 使用版本号实现乐观锁

  1. 在表中添加一个版本字段,例如 version
  2. 读取记录时也读取版本信息。
  3. 更新记录时,根据版本号进行条件判断;
  4. 如果 UPDATE 语句影响的行数为0,说明在尝试更新的过程中,已经有其他事务修改了该记录,这时可以采取相应的措施,如提示用户数据已更改、重试等。

 比如这个SQL语句,更新会将版本号+1,同时只有版本号未有其他操作时才能执行成功。

UPDATE table_name
SET column1 = value1, column2 = value2, version = version + 1
WHERE id = some_id AND version = current_version;

 这种方式的优点是避免了锁定资源,提高了并发性能,但缺点是在高并发场景下可能会出现较多的重试情况。

1.2 使用时间戳实现乐观锁

第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp),和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

此方案有缺点,就是当并发事务时间间隔小于当前系统平台的最小时间单位时,会发生覆盖前一个事务结果的问题。

2. Mybatis实现乐观锁

通常的做法是通过版本号(version)字段来实现 

<insert id="isExistsUser" >
    select count(1) from t_users where userId = #{id}
</insert>

<select id="selectVersion" parameterType="user" resultType="long" >
select version from  t_users   where userName = #{userName} 
</select>

<update id="updateByVersion" parameterType="user">
update t_users set  version=version+1, password= #{password} where  userName = #{userName} and version=#{version}
</update>

<select id="selectUsers" resultType="int">
  select count(1)
  from t_users
  where id = #{id}
</select>

程序逻辑实现:

int userCount = UserMapper.selectUsers(id);
if (userCount==0) 
{
    Long version = UserMapper.selectVersion(user);
    int call = 0;
    user.setVersion(version);
    while (UserMapper.updateByVersion(user)==0) 
    {
        if (call++==3) 
        {
            break;
        }
    }
}

3. MyBatis-Plus实现乐观锁

以下时基于SpringBoot的实现,与非此方法大相径庭

3.1 添加依赖

首先确保你的项目中已经添加了 MyBatis-Plus 的依赖。如果你使用的是 Maven,可以在 pom.xml 文件中加入以下依赖:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>版本号</version>
</dependency>

3.2. 配置乐观锁插件

在 Spring Boot 应用程序的配置类或主类中,你需要配置 MyBatis-Plus 的乐观锁插件。通常这一步是通过 MybatisPlusConfig 类来完成的。

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

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

3.3. 实体类设置

在实体类中,需要添加一个字段来作为版本号。MyBatis-Plus 默认会识别名为 version 或带有 @Version 注解的字段作为乐观锁的版本号。

import com.baomidou.mybatisplus.annotation.Version;

public class ExampleEntity {
    private Long id;
    private String data;
    
    @Version
    private Integer version;

    // getters and setters
}

或者,如果你的版本字段名不是 version,你可以直接使用 @Version 注解指定它:

import com.baomidou.mybatisplus.annotation.Version;

public class ExampleEntity {
    private Long id;
    private String data;
    
    @Version
    private Integer optimisticLockVersion;  // 自定义名称

    // getters and setters
}

注意事项

  • 支持的数据类型包括:intIntegerlongLongDateTimestampLocalDateTime
  • 对于整数类型,newVersion 是 oldVersion + 1
  • newVersion 会自动回写到实体对象中。
  • 支持内置的 updateById(entity) 和 update(entity, wrapper)saveOrUpdate(entity)insertOrUpdate(entity) (version >=3.5.7) 方法。
  • 自定义方法更新时如果满足内置参数的参数条件方式也会执行乐观锁逻辑,例如自定义myUpate(entity) 这个和 updateById(entity) 是等价的,会提取参数进行乐观锁填充,但更新实现需要自行处理。
  • 在 update(entity, wrapper) 方法中,wrapper 不能复用。

3.4. 使用乐观锁

当你更新数据时,MyBatis-Plus 会自动处理乐观锁逻辑。例如:

@Service
public class ExampleService {
    @Autowired
    private ExampleMapper exampleMapper;

    @Transactional
    public void updateData(Long id, String newData) {
        ExampleEntity entity = exampleMapper.selectById(id);
        if (entity == null) {
            throw new RuntimeException("Entity not found");
        }

        entity.setData(newData);
        int result = exampleMapper.updateById(entity);

        if (result == 0) {
            throw new OptimisticLockingFailureException("失败了,请重试");
        }
    }
}

 这里,当调用 updateById 方法时,MyBatis-Plus 会自动检查并更新版本号。如果在尝试更新时发现版本号不匹配(即数据已被其他事务修改),则更新操作不会成功,返回值将是 0,这时可以抛出异常或进行重试。

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

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

相关文章

设置ip和代理DNS的WindowsBat脚本怎么写?

今天分享一个我们在工作时&#xff0c;常见的在Windows中通过批处理脚本&#xff08;.bat 文件&#xff09;来设置IP地址、代理以及DNS 相关配置的示例&#xff0c;大家可以根据实际需求进行修改调整。 一、设置静态IP地址脚本示例 以下脚本用于设置本地连接&#xff08;你可…

深度学习-49-AI应用实战之基于HyperLPR的车牌识别

文章目录 1 车牌识别系统1.1 识别原理1.1.1 车牌定位1.1.2 字符识别2 实例应用2.1 安装hyperlpr32.2 识别结果2.3 可视化显示2.4 结合streamlit3 附录3.1 PIL.Image转换成OpenCV格式3.2 OpenCV转换成PIL.Image格式3.3 st.image嵌入图像内容3.4 参考附录1 车牌识别系统 车牌识别…

基于深度学习的手势识别算法

基于深度学习的手势识别算法 概述算法原理核心逻辑效果演示使用方式参考文献 概述 本文基于论文 [Simple Baselines for Human Pose Estimation and Tracking[1]](ECCV 2018 Open Access Repository (thecvf.com)) 实现手部姿态估计。 手部姿态估计是从图像或视频帧集中找到手…

【Linux】-操作系统

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;深入代码世界&#xff0c;了解掌握 Linux 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ​​ 一、冯•诺依曼架构&#xff…

2024最新python使用yt-dlp

2024最新python使用yt-dlp下载YT视频 1.获取yt的cookie1&#xff09;google浏览器下载Get cookies.txt LOCALLY插件2&#xff09;导出cookie 2.yt-dlp下载[yt-dlp的GitHub地址](https://github.com/yt-dlp/yt-dlp?tabreadme-ov-file)1&#xff09;使用Pycharm(2024.3)进行代码…

Mybatis集成篇(一)

Spring 框架集成Mybatis 目前主流Spring框架体系中&#xff0c;可以集成很多第三方框架&#xff0c;方便开发者利用Spring框架机制使用第三方框架的功能。就例如本篇Spring集成Mybatis 简单集成案例&#xff1a; Config配置&#xff1a; Configuration MapperScan(basePack…

C51相关实验

C51相关实验 LED (P2 / 0~7)蜂鸣器 (P2^5)数码管 (P0 0~7 段 &#xff0c;P2 2~4 位)独立按键 &#xff08;P3^1 P3^0 P3^2 P3^3&#xff09;直流电机 (J47 5v 01~04)综合实验矩阵按键 (P1组 0~7)LED点阵 LED (P2 / 0~7) //功能&#xff1a;1.让开发板的LED全亮&#xff0c;2,…

C++语法·叭

阁下何不乘风起&#xff0c;扶摇直上九万里。 qi fei 目录 内存管理 分区介绍 1.栈区&#xff1a; 2.内存映射段&#xff1a; 3.堆&#xff1a; 4.数据段&#xff1a; 5.代码段&#xff1a; 补充&#xff1a; C内存管理&#xff08;简略回忆&#xff09; C内存…

数据库期末复习题库

1. Mysql日志功能有哪些? 记录日常操作和错误信息&#xff0c;以便了解Mysql数据库的运行情况&#xff0c;日常操作&#xff0c;错误信息和进行相关的优化。 2. 数据库有哪些备份方法 完全备份&#xff1a;全部都备份一遍表备份&#xff1a;只提取数据库中的数据&#xff0…

矩阵重新排列——rot90函数

通过 r o t 90 rot90 rot90函数可以将矩阵进行旋转 用法&#xff1a; r o t 90 ( a , k ) rot90(a,k) rot90(a,k)将矩阵 a a a按逆时针方向旋转 k 9 0 ∘ k\times90^\circ k90∘

挑战用React封装100个组件【001】

项目地址 https://github.com/hismeyy/react-component-100 组件描述 组件适用于需要展示图文信息的场景&#xff0c;比如产品介绍、用户卡片或任何带有标题、描述和可选图片的内容展示 样式展示 代码展示 InfoCard.tsx import ./InfoCard.cssinterface InfoCardProps {ti…

联通云服务器部署老项目tomcat记录

1.先在服务器上安装mysql和tomcat 2.tomcat修改端口 3.在联通云运控平台配置tomcat访问端口&#xff08;相当于向外部提供可访问端口&#xff09; 4.将tomcat项目放在服务器tomcat的webapps里面 5.在mysql里创建项目数据库&#xff0c;运行sql创建表和导入数据 6.在配置文…

Python 删除Word中的表格

在处理Word文档时&#xff0c;我们经常会遇到需要删除表格的情况。无论是为了简化文档结构&#xff0c;还是为了更新内容&#xff0c;删除表格都是一个常见的操作。但是通过手动删除不仅耗时&#xff0c;而且容易出错&#xff0c;本文将介绍如何使用Python通过编程删除Word中的…

讯飞语音转写WebApi 【JS语言】

讯飞语音转写 API 文档 文档地址&#xff1a;https://www.xfyun.cn/doc/asr/ifasr_new/API.html 看到没有 js 版本的 demo&#xff08;音频流模式&#xff09;&#xff0c;所以就搞了一个分享出来 在 React Native 运行环境下测试有效。 1、生成 signa import axios from a…

c++基础开发环境vscode+mingw-w64

c开发需要的基础有两个&#xff1a;编译环境&#xff0c;开发环境。 最简单的编译环境可以用gcc&#xff0c;cl&#xff0c;clongllvm; 开发环境最简单直接用文本编辑器就可以。 但是实际开发都会用ide来做&#xff0c;现代的ide即有开发环境可以写代码&#xff0c;自动补全&am…

DBA面试题-1

面临失业&#xff0c;整理一下面试题&#xff0c;找下家继续搬砖 主要参考&#xff1a;https://www.csdn.net/?spm1001.2101.3001.4476 略有修改 一、mysql有哪些数据类型 1&#xff0c; 整形 tinyint,smallint,medumint,int,bigint&#xff1b;分别占用1字节、2字节、3字节…

LSTM卫星轨道预测(一)

一.多文件预测 代码详细解析 1. 文件读取与数据处理 功能 从 .sp3 文件中读取卫星轨迹数据。提取包括 Satellite_ID, X, Y, Z 等字段的信息。计算派生特征&#xff08;如速度和加速度&#xff09;&#xff0c;便于后续建模使用。 主要函数&#xff1a;extract_sp3_data(fil…

如何通过智能生成PPT,让演示文稿更高效、更精彩?

在快节奏的工作和生活中&#xff0c;我们总是追求更高效、更精准的解决方案。而在准备演示文稿时&#xff0c;PPT的制作往往成为许多人头疼的问题。如何让这项工作变得轻松且富有创意&#xff1f;答案或许就在于“AI生成PPT”这一智能工具的广泛应用。我们就来聊聊如何通过这些…

格网法计算平面点云面积(matlab版本)

1、原理介绍 格网法计算平面点云面积&#xff0c;其思想类似高中油膜法计算面积。其将点云投影到水平面&#xff0c;再将点云划分成尺寸相同的格网。最后&#xff0c;统计格网内包含点的数量number&#xff0c;那么可利用如下公式计算得到点云的面积&#xff1a; Aeranumber*L…

无代码实现可视化GIS+模型+三维

现在的工具是越来越方便了&#xff0c;本来不是做前端的。可以节省很多的人力和时间&#xff0c;更快的搭建自己想要的可视化大屏&#xff0c;看例子 主要由三维的gis地图和模型加上二维的数据表格分析来实现这个可视化界面。 gis地图的设置 每一个gis都要设置世界远点&#x…