悲观锁、乐观锁、mybatis-plus实现乐观锁

转载自:www.javaman.cn

1、悲观锁、乐观锁

乐观锁和悲观锁是两种用于处理并发操作的数据锁定策略。它们在处理多个事务尝试同时访问和修改同一数据时的方法有所不同。

  1. 悲观锁 (Pessimistic Locking)

    • 概念:悲观锁是一种基于悲观态度的数据并发控制机制。它总是假设最坏的情况,即认为其他事务会尝试修改数据,因此在读取数据时就会加锁,以确保在此期间其他事务不能修改数据。
    • 工作原理:当一个事务想要读取或修改数据时,它会先请求锁。如果锁已经被其他事务持有,则当前事务会被阻塞,直到锁被释放。这确保了每次只有一个事务可以修改数据。
    • 使用场景:悲观锁适用于写操作较多的场景,或者当数据冲突可能性较高时。它可以在数据库层面实现,如行锁、表锁等。
    • 优点:能够有效防止数据冲突,确保数据的一致性。
    • 缺点:如果锁的粒度过大或持有时间过长,可能导致并发性能下降和资源浪费。
  2. 乐观锁 (Optimistic Locking)
    • 概念:乐观锁是基于乐观态度的数据并发控制机制。它总是假设最好的情况,即在读取数据和提交更新之间,其他事务不会修改数据。因此,它不会在读取数据时加锁,而是在更新数据时检查是否有其他事务已经修改了数据。
    • 工作原理:通常通过版本号、时间戳等机制实现。当事务想要更新数据时,它会检查数据的版本号是否与自己最初读取的版本号相匹配。如果匹配,说明没有其他事务修改过数据,可以进行更新;否则,更新会被拒绝。
    • 使用场景:乐观锁适用于读操作较多、写操作较少的场景,或者当数据冲突可能性较低时。它通常在应用层面实现。
    • 优点:在高并发场景下可以提高性能,因为它减少了不必要的锁等待时间。
    • 缺点:如果有很多写操作或者数据冲突频繁发生,可能导致大量的重试和回滚,从而降低性能。

实战中使用

  • 悲观锁:在关系型数据库中,如MySQL,可以使用SELECT ... FOR UPDATE语句对选定的行或表加锁。在Java中,可以使用synchronized关键字或ReentrantLock等来实现悲观锁。
  • 乐观锁:可以在应用层面实现,例如在更新数据时检查数据的版本号是否发生变化。在MyBatis-Plus中,可以通过OptimisticLockerInnerInterceptor插件来简化乐观锁的使用。

2、mybatis-plus实现乐观锁

MyBatis-plus本身并不直接实现悲观锁或乐观锁,而是提供了与数据库的交互机制,使得开发者能够在应用中实现这两种锁策略。但是,为什么我们经常会看到 MyBatis 与乐观锁的结合,而与悲观锁的结合较少呢?这主要是因为两者在使用场景和适用性上的差异。

  1. 悲观锁

    • 悲观锁主要在数据库层面实现,例如通过 SQL 语句。
    • 当使用悲观锁时,事务在读取数据时就会加锁,确保在此期间其他事务不能修改数据。这涉及到数据库的并发控制和锁定机制,与 MyBatis 的 ORM 功能关系不大。
    • 由于悲观锁的实现更多地依赖于数据库本身的功能,因此 MyBatis 在这方面并没有太多可以增加的价值。
  2. 乐观锁
    • 乐观锁通常在应用层面实现,需要开发者检查数据的版本号、时间戳等来判断数据是否在读取后被其他事务修改。
    • MyBatis-Plus 提供的 OptimisticLockerInnerInterceptor 插件可以简化这一过程,帮助开发者更容易地在应用中实现乐观锁。
    • 由于乐观锁的实现更多地依赖于应用逻辑,MyBatis 在这方面的插件和工具可以为开发者带来便利。

总结:MyBatis 本身并不防止悲观锁或乐观锁,而是提供了与数据库的交互机制。悲观锁主要依赖于数据库的功能来实现,而乐观锁则可以在应用层面得到 MyBatis-Plus 等工具的帮助。

乐观锁的基础使用

MyBatis-Plus 提供了一个内置的乐观锁插件 OptimisticLockerInnerInterceptor 来帮助简化乐观锁的实现。以下是使用 MyBatis-Plus 实现乐观锁的基本步骤:

​ 1.添加乐观锁插件

在你的 MyBatis-Plus 配置中添加乐观锁插件。

@Configuration
@MapperScan({"com.ds.blog.system.mapper","com.ds.blog.admin.mapper"})
public class MybatisPlusConfig { @Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//乐观锁插件
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}

​ 2.标记乐观锁字段

在你的实体类中,使用 @Version 注解来标记作为乐观锁字段的属性,通常是版本号或时间戳。

public class Entity {
@Version
private Integer version;
// 其他字段和方法
}
  1. 更新操作

    当你尝试更新数据时,MyBatis-Plus 会自动检查乐观锁字段。如果数据的版本号与你最初读取的版本号不匹配,更新会被拒绝,并抛出 OptimisticLockException 异常。
  2. 处理乐观锁异常

    在你的业务代码中,需要捕获并处理 OptimisticLockException 异常。通常的做法是重试更新操作或通知用户数据已被其他事务修改。
  3. 自定义乐观锁逻辑

    如果需要更复杂的乐观锁逻辑,你可以实现自己的乐观锁拦截器,并覆盖默认的行为。

注意:乐观锁策略的成功与否还取决于你的并发控制策略和业务场景。

自定义乐观锁拦截器

具体步骤如下:

​ 1.创建自定义拦截器类

首先,你需要创建一个类来实现 MyBatis-Plus 的 InnerInterceptor 接口。这个接口定义了一些方法,允许你在 SQL 执行的不同阶段插入自定义逻辑。

import com.baomidou.mybatisplus.core.parser.SqlInfo;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*; import java.util.Properties; @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class CustomOptimisticLockInterceptor implements InnerInterceptor {
// 你的自定义逻辑将在这里实现
}

​ 2.实现拦截方法

在你的自定义拦截器类中,你需要实现 processBeforeprocessAfter 方法。这些方法在 SQL 执行之前和之后被调用,允许你插入自定义逻辑。在这个例子中,我们关注 processBefore 方法,因为它允许我们在更新操作之前检查乐观锁。

@Override
public void processBefore(Executor executor, MappedStatement ms, Object parameter, String sql, SqlInfo sqlInfo) {
// 获取当前事务尝试更新的实体对象
Entity entity = (Entity) parameter;
// 获取原始版本号(通常从数据库中读取)
int originalVersion = entity.getVersion();
// 检查版本号是否已经被修改(意味着有其他事务已经更新了这条记录)
if (originalVersion != entity.getVersion()) {
throw new OptimisticLockException("数据已被其他事务修改");
}
// 如果需要检查其他字段或执行其他逻辑,可以在这里添加代码
}

​ 3.注册自定义拦截器

在你的 MyBatis-Plus 配置中,你需要注册你的自定义拦截器,以便它能够被正确地应用到你的 SQL 执行过程中。

@Configuration
@MapperScan({"com.ds.blog.system.mapper","com.ds.blog.admin.mapper"})
public class MybatisPlusConfig { @Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new CustomOptimisticLockInterceptor());
return mybatisPlusInterceptor;
}

悲观锁、乐观锁、mybatis-plus实现乐观锁的更多相关文章

  1. mybatis 如何使用乐观锁

    悲观锁的问题: 因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是 ...

  2. 对mysql乐观锁、悲观锁、共享锁、排它锁、行锁、表锁概念的理解

    乐观锁 乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了. 实现: 通常实现是 ...

  3. MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解

    文章出处:https://www.souyunku.com/2018/07/30/mysql/?utm_source=tuicool&utm_medium=referral MySQL/Inn ...

  4. Redis专题(3):锁的基本概念到Redis分布式锁实现

    拓展阅读:Redis闲谈(1):构建知识图谱 Redis专题(2):Redis数据结构底层探秘 近来,分布式的问题被广泛提及,比如分布式事务.分布式框架.ZooKeeper.SpringCloud等等 ...

  5. 你用对锁了吗?浅谈 Java “锁” 事

    每个时代,都不会亏待会学习的人 大家好,我是yes. 本来打算继续写消息队列的东西的,但是最近在带新同事,发现新同事对于锁这方面有一些误解,所以今天就来谈谈"锁"事和 Java 中 ...

  6. Redis 分布式锁,C#通过Redis实现分布式锁(转)

    目录(?)[+] 分布式锁一般有三种实现方式: 可靠性   分布式锁一般有三种实现方式: 1. 数据库乐观锁; 2. 基于Redis的分布式锁; 3. 基于ZooKeeper的分布式锁.本篇博客将介绍 ...

  7. (转)SQL SERVER的锁机制(一)——概述(锁的种类与范围)

    锁定:通俗的讲就是加锁.锁定是 Microsoft SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数 ...

  8. InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!

    InnoDB行锁是通过索引上的索引项来实现的,这一点MySQL与Oracle不同,后者是通过在数据中对相应数据行加锁来实现的. InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoD ...

  9. mysql READ-COMMITTED 模式下 行锁不会升级到表级锁

    mysql> select sn,id,info from s100 group by id; +-----+------+------+ | sn | id | info | +-----+- ...

  10. (转)Synchronized(对象锁)和Static Synchronized(类锁)的区别

    场景:面试的时候经常用得到! 1 综述 Synchronized和Static Synchronized区别 一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念),一个是全 ...

随机推荐

  1. 知识图谱(Knowledge Graph)- Neo4j 5.10.0 CentOS 安装

    知识图谱(Knowledge Graph)- Neo4j 5.10.0 Docker 安装 知识图谱(Knowledge Graph)- Neo4j 5.10.0 CentOS 安装 https:// ...

  2. vue3+vite2动态绑定图片优雅解决方案

    优雅解决方案在最下面,小伙伴们儿可以直接前往 背景 在vue3+vite2项目中,我们有时候想要动态绑定资源,比如像下面的代码这样: <template> <div> < ...

  3. 《SQL与数据库基础》01. SQL概述 · 分类

    目录 SQL概述 SQL语法特征 SQL分类 本文以 MySQL 为例 SQL概述 SQL(Structured Query Language),结构化查询语言,用于访问和处理数据库的标准的计算机语言 ...

  4. Linux虚拟机安装及下载

    centos 7操作系统下载及安装步骤 (仅供参考) 下载: 1.打开如下网站:先下载镜像文件 ping:https://www.centos.org/download/ 2.进入到如下界面 3.然后 ...

  5. Linux部署项目常用命令(持续更新)

    防火墙配置 # 启动防火墙服务 systemctl start firewalld # 关闭防火墙服务 systemctl stop firewalld # 查看防火墙服务状态 systemctl s ...

  6. 基于FPGA 的SDRAM控制器

    SDRAM基本信息 储存能力计算 4X16X4=256(Mbit),注意不是MByte SDRAM控制 sdram包含两个部分:sdram_ctrl.fifo_ctrl. sdram_ctrl:其顶层 ...

  7. 算法——AcWing算法提高课中代码和题解

    文章目录 第一章 动态规划 (完成情况:64/68) 数字三角形模型 最长上升子序列模型 背包模型 状态机模型 状态压缩DP 区间DP 树形DP 数位DP 单调队列优化DP 斜率优化DP 第二章 搜索 ...

  8. 第七单元《中国传统文化与管理》单元测试 mooc

    第七单元<中国传统文化与管理>单元测试 返回 本次得分为:8.00/10.00, 本次测试的提交时间为:2020-08-30, 如果你认为本次测试成绩不理想,你可以选择 再做一次 . 1 ...

  9. Capture Data.dmg

    苹果apple mac 系统检测  日常分析  软件 https://gigafiles.apple.com/#/download 现有文件可供下载. 备注 Capture Data 9.9.0 Th ...

  10. Jmeter调用Python脚本,实现参数互相传递

    首先传值到python 1:新增取样器--->os进程取样器 2:新建.bat文件 (写python脚本的路径和传参的个数:思路是:jmeter调用shell,用shell执行py) F:cd ...