首页 > 其他分享 >乐观锁,悲观锁

乐观锁,悲观锁

时间:2024-12-26 09:30:04浏览次数:8  
标签:事务 加锁 -- 乐观 版本号 version 悲观 balance

乐观锁悲观锁是两种常见的并发控制机制,主要用于解决并发操作中的数据一致性问题。它们的应用场景和实现方式各有特点:


1. 乐观锁

定义

  • 乐观锁基于乐观的并发控制思想,假设事务间的冲突概率较低,因此不对资源加锁。
  • 在更新数据时,通过某种机制(如版本号或时间戳)来检测是否发生了冲突,如果检测到冲突,事务会回滚或重试。

实现方式

  1. 在表中增加一个版本号字段version)或时间戳字段
  2. 读取数据时一并读取版本号。
  3. 更新时将版本号作为条件,如果版本号没有变化,则允许更新;否则,更新失败。

SQL 示例

-- 假设有一个版本号字段 version

-- 事务 A 读取数据
SELECT balance, version FROM accounts WHERE id = 1;

-- 事务 A 更新数据,条件是版本号未被其他事务修改
UPDATE accounts
SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 1;

-- 如果条件未满足(版本号不匹配),更新失败,需要重试。

特性

  • 优点
    • 无需加锁,对读取操作没有阻塞,性能较高。
    • 适合读多写少的场景。
  • 缺点
    • 如果发生冲突,可能需要多次重试,增加了应用程序的复杂度。

2. 悲观锁

定义

  • 悲观锁基于悲观的并发控制思想,假设事务间的冲突概率较高,因此对资源加锁以避免冲突。
  • 在读取数据时直接加锁,确保其他事务无法修改或读取该数据。

实现方式

  • 通过数据库提供的锁机制(如共享锁(S 锁)排他锁(X 锁))来实现。
  • 常用语法:
    • 共享锁LOCK IN SHARE MODE
    • 排他锁FOR UPDATE

SQL 示例

-- 悲观锁使用排他锁,防止其他事务修改该行数据
START TRANSACTION;

-- 读取数据并加排他锁
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;

-- 更新数据
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

COMMIT;

特性

  • 优点
    • 通过锁机制保证数据一致性,不需要额外的版本检测。
    • 适合写多读少高并发更新的场景。
  • 缺点
    • 会阻塞其他事务的操作,可能导致性能降低。
    • 容易发生死锁,需要特别注意加锁顺序。

3. 乐观锁与悲观锁的对比

特性 乐观锁 悲观锁
加锁机制 不加锁,通过版本号或时间戳控制并发 通过数据库锁机制加锁
适用场景 读多写少,冲突概率低 写多读少,冲突概率高
并发性能 性能较高,无锁操作 性能较低,可能阻塞其他事务
冲突处理 冲突时需要回滚或重试 无冲突,直接完成事务
实现复杂度 需要应用逻辑支持(版本号或时间戳) 数据库原生支持
事务阻塞 不会阻塞其他事务 可能阻塞其他事务

4. 如何选择

  1. 乐观锁适合以下场景:

    • 读操作频繁、写操作较少。
    • 数据冲突概率较低。
    • 对系统性能要求较高。
  2. 悲观锁适合以下场景:

    • 写操作频繁。
    • 冲突概率较高,需要严格的数据一致性。
    • 数据库支持较好,可以接受一定的阻塞。

5. 综合示例

假设一个账户余额更新系统,多个事务可能同时读取和更新账户余额:

乐观锁

事务读取时不加锁,更新时检测版本号是否变化。

-- 读取数据
SELECT balance, version FROM accounts WHERE id = 1;

-- 更新数据
UPDATE accounts
SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 1;

悲观锁

事务读取时加锁,防止其他事务同时操作。

START TRANSACTION;
-- 读取并加锁
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;

-- 更新
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

COMMIT;

通过选择合适的锁机制,可以在性能和一致性之间找到平衡。

注意:该内容由由AIGC提供。

标签:事务,加锁,--,乐观,版本号,version,悲观,balance
From: https://www.cnblogs.com/dx5800/p/18567972

相关文章

  • 乐观锁与悲观锁
    独占锁独占锁是一项悲观技术——它假设最坏的情况(如果你不锁门,那么捣蛋鬼就会闯入并搞得一团糟),并且只有在确保其他线程不会造成干扰(通过获取正确的锁)的情况下才能执行的下去。乐观锁对于细粒度的操作,还有另外一种更高效的方法,也是一种乐观的方法,通过这种方法可以在不发生干......
  • MySQL 的乐观锁和悲观锁是什么?
    MySQL的乐观锁和悲观锁是什么?在并发环境下,为了避免数据竞争和保证数据一致性,可以使用不同的锁策略。乐观锁和悲观锁是两种常见的并发控制机制,它们在锁定数据时的理念和实现方式上有显著区别。1.悲观锁(PessimisticLock)定义悲观锁是一种保守的并发控制策略,假设数据在被访问......
  • MySQL的各种锁(表锁,行锁,悲观锁,乐观锁,间隙锁,死锁)
    对于UPDATE、DELETE、INSERT语句,InnoDB会自动给涉及数据集加排他锁(X)。而MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行增、删、改操作前,会自动给涉及的表加写锁,这个过程并不需要我们去手动操作。那么在特定情况下,我们该如何去加锁呢?下面咱们来认真的......
  • MybatisPlus入门(十一)MybatisPlus-乐观锁
    一、乐观锁修改操作中的问题;乐观锁,琐是用来解决并发问题的。例如秒杀业务,上了100个秒杀单子,如果到了最后一个,8个人一起买,会出现问题,卖出第0号-1号-2号,小型并发解决方案:乐观锁。二、Mybatis-Plus乐观锁实现步骤Mybatis-Plus乐观锁实现步骤:步骤一......
  • 深入剖析 MyBatis-Plus:操作总结、对比与实践案例(CRUD 操作、分页、条件构造器、自动填
    MyBatis-Plus是MyBatis的增强工具,它极大简化了MyBatis的配置和操作,提高了开发效率。本文从基本操作到高阶用法,详细介绍了MyBatis-Plus的常见功能及与MyBatis的区别,并通过实际案例展示其强大的扩展能力。MyBatis-Plus基于MyBatis,但旨在减少开发者的代码量,增强可......
  • 【Java】并发编程的艺术:悲观锁、乐观锁与死锁管理
    目录一、乐观锁和悲观锁二、ReadWriteLock三、StampedLock四、Semaphore五、死锁的条件六、如何发现死锁七、如何避免死锁一、乐观锁和悲观锁        悲观锁(PessimisticLocking)具有强烈的独占和排他特性。它指的是对数据被外界修改持保守态度。因此,在整......
  • [官翻]mysqlbackup的乐观备份
    乐观备份可以用来提升备份和恢复体量比较大的数据库(只有少量的表经常变更)的性能。2)在大型数据库的热备份过程中(例如,以TB为单位),当备份进行时,可能会在服务器上生成巨大的重做日志文件。由于重做日志文件的增长速度快于mysqlbackup处理的速度,因此当mysqlbackup无法赶上重做日志周期,并......
  • [MySQL]实现乐观锁
    使用版本号在MySQL中,可以通过使用版本号(Version)来实现乐观锁。一种常见的实现方式是在表中增加一个版本号字段,每次更新数据时,都需要比对版本号。如果版本号一致,表示可以进行更新操作,否则表示其他事务已经修改了数据,需要进行相应的处理。下面是一个简单的示例,演示如何在MySQL......
  • MySQL锁机制揭秘:从行锁到表锁,共享锁到排他锁,悲观锁到乐观锁的全面解读
    MySQL有哪些锁1、按照锁的粒度划分行锁是最低粒度的的锁,锁住指定行的数据,加锁的开销较大,加锁较慢,可能会出现死锁的情况,锁的竞争度会较低,并发度相对较高。但是如果where条件里的字段没有加索引,则加的行锁会自动升级为表锁,因为行锁是基于索引去进行操作的,所以想要加行锁,就......
  • 悲观锁,乐观锁
    悲观锁:一上来就加锁,每次只能一个线程进来,访问完毕后再解锁。乐观锁:一上来不上锁,认为是没有问题的,大家一起跑,等出现线程安全时才开始控制。  publicclassTest1{privatestaticAtomicIntegercount=newAtomicInteger(0);publicstaticvoidmain(String[]args)......