[ruby on rails]乐观锁和悲观锁

  • 锁,分为悲观锁(Pessimistic)和乐观锁(Optimistic).
  • 对比的话,可以笼统的理解悲观锁是数据库层面,而乐观锁是应用层面

一、悲观锁(Pessimistic)

  • 特性
    强烈的独占和排他。
    它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。
  • 实现
    往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
    一个典型的依赖数据库的悲观锁调用:
    select * from account where name="Erica" for update;
    这条 sql 语句锁定了 account 表中所有符合检索条件(name=“Erica”)的记录。 本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。
    注意:根据 name 是否有索引、是否是唯一索引、是否是主键,决定锁全表、区间、单个记录。
"select * from where sku xxx for update" 时,在 repeat read的隔离级别下,MySQL 加锁机制取决于sku的索引

> 如果 sku 没有索引,则锁全表。
> 如果 sku 有普通索引,则锁一个区间 - range lock。
> 如果 sku 是唯一索引,仅仅锁一行。
> 如果 sku 是主键,仅仅锁一行。
  • 应用场景
    一般对于资源的争用都可以使用悲观锁,比如电商系统中涉及到订单的部分,比如用户支付完成后可能会同时有多条支付成功的通知(做过支付的都知道一般有同步通知和异步通知),比如订单改价的同时可能用户正在支付等等,对于这种会对订单状态发生改变的操作,我们内部一般对这种操作都做加锁处理。
  • Rails 的悲观锁
    相关方法有:lock、lock! 和 with_lock.

lock 和 with_lock 都是封装 lock! 而来。
lock 相当于 lock! 的别名,但调用者可以是 relation 对象。
with_lock 和事务捆绑在一起,并且参数可以是代码块。

使用举例:

# 使用 lock,注意生成的 SQL
Account.lock.find(1) # 注意,这种最终会导致一个行锁
# SELECT `accounts`.* FROM `accounts` WHERE `accounts`.`id` = 1 LIMIT 1 FOR UPDATE

# lock 结合 transaction 一起使用
Account.transaction do
  # select * from accounts where name = 'shugo' limit 1 for update
  shugo = Account.where("name = 'shugo'").lock(true).first  # 注意,这里可不是行锁,这里会是一个表锁
  yuko = Account.where("name = 'yuko'").lock(true).first
  shugo.balance -= 100
  shugo.save!
  yuko.balance += 100
  yuko.save!
end
  • 如果查询的条件没有落在索引上,最好不要这样来用。折中一下,我们不愿意在处理一条数据时把整张表都锁住,但是又没有办法直接找到数据行的id,可以这么做:
# 使用 lock!
Account.transaction do
  # select * from accounts where ...
  accounts = Account.where(...)
  account1 = accounts.detect {
    |account| ... }
  account2 = accounts.detect {
    |account| ... }

  # account1 和 account2 只能是单个对象
  # select * from accounts where id=? for update
  account1.lock!
  account2.lock!
  account1.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值