MySQL中的悲观锁和乐观锁

本文探讨了悲观锁的数据库锁机制与乐观锁的版本号策略,分析了它们在并发控制中的优缺点,特别强调了乐观锁在读多写少场景中的适用性和可能出现的性能挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1:悲观锁

顾名思义,就是对于数据的处理持悲观态度,总认为会发生并发冲突,获取和修改数据时,别人会修改数据。所以在整个数据处理过程中,需要将数据锁定。
悲观锁的实现,通常依靠数据库提供的锁机制实现,比如mysql的排他锁,select .... for update来实现悲观锁。
将商品库存数量nums字段类型设为unsigned,保证在数据库层面不会发生负数的情况。
悲观锁在并发控制上采取的是先上锁然后再处理数据的保守策略,虽然保证了数据处理的安全性,但也降低了效率。

2:乐观锁

顾名思义,就是对数据的处理持乐观态度,乐观的认为数据一般情况下不会发生冲突,只有提交数据更新时,才会对数据是否冲突进行检测。
如果发现冲突了,则返回错误信息给用户,让用户自已决定如何操作。
乐观锁的实现不依靠数据库提供的锁机制,需要我们自已实现,实现方式一般是记录数据版本,一种是通过版本号,一种是通过时间戳。
给表加一个版本号或时间戳的字段,读取数据时,将版本号一同读出,数据更新时,将版本号加1。
当我们提交数据更新时,判断当前的版本号与第一次读取出来的版本号是否相等。如果相等,则予以更新,否则认为数据过期,拒绝更新,让用户重新操作。

乐观锁是基于程序实现的,所以不存在死锁的情况,适用于读多的应用场景。如果经常发生冲突,上层应用不断的让用户进行重新操作,
这反而降低了性能,这种情况下悲观锁就比较适用。

MySQL 中的悲观锁乐观锁是两种处理并发访问数据一致性的机制,它们在实现方式、适用场景以及性能特点上有显著区别。 ### 悲观锁 悲观锁假设并发冲突经常发生,因此在整个数据处理过程中对数据保持锁定状态,以确保数据的完整性。悲观锁实现通常依赖于数据库提供的锁机制,例如行锁、读锁写锁等。这种锁机制在操作开始前就对数据加锁,直到操作完成才会释放锁。悲观锁适用于写入频繁且冲突概率较高的场景,例如金融交易系统,对数据一致性要求极高,无法容忍中间状态的错误。 在实际应用中,悲观锁通过 `SELECT ... FOR UPDATE` 或 `SELECT ... LOCK IN SHARE MODE` 等语句实现,确保数据在事务处理期间不被其他事务修改 [^3]。 ### 乐观锁 乐观锁则假设并发冲突较少,因此在数据操作时不立即加锁,而是在提交更新时检查是否有冲突发生。乐观锁实现通常依赖于版本号(Version)、时间戳(Timestamp)或比较交换(CAS)机制。如果在提交时检测到冲突,则拒绝操作并提示重试。这种锁机制适用于读取频繁且冲突概率较低的场景,例如统计数据的更新或低并发环境下的数据读取。 乐观锁的一个常见实现方式是通过版本号字段。在更新数据前,会检查当前版本号是否与数据库中的版本号一致,若一致则允许更新并增加版本号;否则,更新失败并提示冲突 [^2]。 ### 适用场景 - **悲观锁适用场景**: - **高冲突场景**:当系统中存在大量并发写入操作,冲突概率较高时,悲观锁可以有效避免数据不一致的问题。 - **数据敏感性高**:如金融系统中的交易处理,对数据一致性要求极高,不能容忍任何中间状态的错误。 - **实时性要求高**:需要立即获取数据并进行修改的场景,悲观锁可以确保数据在操作期间不会被其他事务修改 [^4]。 - **乐观锁适用场景**: - **低冲突场景**:当系统中读取操作远多于写入操作,且并发冲突概率较低时,乐观锁可以减少锁的开销,提高系统吞吐量。 - **允许重试**:在某些场景下,系统可以容忍操作失败并进行重试,此时乐观锁更为合适。 - **数据一致性要求适中**:对于某些非关键数据,如统计数据或日志信息,允许一定程度上的不一致,乐观锁可以提供更好的性能 [^2]。 ### 总结 悲观锁乐观锁各有优劣,选择合适的锁机制应根据具体的业务需求系统特点来决定。悲观锁适合高冲突、高敏感度的场景,而乐观锁则适合低冲突、高读取频率的场景。理解这两种锁机制的核心思想适用场景,有助于在实际开发中做出更合理的选择 [^4]。 ```sql -- 悲观锁示例:使用 SELECT ... FOR UPDATE 获取行锁 START TRANSACTION; SELECT * FROM accounts WHERE account_id = 1 FOR UPDATE; -- 执行更新操作 UPDATE accounts SET balance = balance - 100 WHERE account_id = 1; COMMIT; -- 乐观锁示例:使用版本号控制并发更新 UPDATE accounts SET balance = balance - 100, version = version + 1 WHERE account_id = 1 AND version = 5; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值