美文网首页Ruby、Rails知识Ruby on RailsRuby
rails中乐观锁和悲观锁的使用

rails中乐观锁和悲观锁的使用

作者: 小新是个程序媛 | 来源:发表于2018-12-18 15:48 被阅读1次

MySQL乐观锁和悲观锁的介绍可以参考之前的一篇文章
MySQL中的锁(行锁,表锁,乐观锁,悲观锁,共享锁,排他锁)

同时补充下,在悲观锁中,对于如下语句的加锁机制,解释如下

"select * from where xxx for update" 

在 repeat read的隔离级别下,MySQL 加锁机制取决于name的索引
如果name没有索引,则锁全表。
如果name 有普通索引,则锁一个区间 - range lock。
如果 name 是唯一索引,仅仅锁一行。
如果name 是主键,仅仅锁一行。

今天主要介绍一下锁在rails中的使用

1. 悲观锁的使用

# select * from accounts where id=1 for update
Account.lock.find(1)
# 注意,这种最终会导致一个行锁

# select * from accounts where name = 'shugo' limit 1 for update
Account.where("name = 'shugo'").lock(true).first
# 注意,这里可能不是行锁,行锁 表锁取决于name字段的属性

Rails 也提供了一个很方便的方法 with_lock'来锁住单个记录,并且内嵌在事务之中。下面代码中的两段是等价的:

account = Account.find(1)
Account.transaction do
    account.lock!
    account.balance -= 100
    account.save! 
end

# 和下面是等价的
account.with_lock do
    account.balance -= 100
    account.save!
end

2. 乐观锁的使用

使用乐观锁之前需要给数据库增加一列 lock_version字段给相应的表,Rails 会自动识别这一列,像数据库提交数据的时候自动带上,如果事务提交失败,那么 Rails 会抛一个 ActiveRecord::StaleObjectError 的异常。
另外,乐观锁是默认打开的,如果要关闭,需要配置一下。

在大鱼系统中,库存管理是使用乐观锁的,流量没那么大,不太可能多个用户同时预订同一个住宿的同一个间夜,概率比较小,所以目前是使用乐观锁来实现的。如果抛异常,那么还可以进行重试。

比如,下面这段代码会进行重试:

retry_times = 3

begin
    @order.with_lock do
        @order.set_paid!
    end
rescue ActiveRecord::StaleObjectError => e
    retry_times -= 1
    if retry_times > 0
        retry
    else
        raise e
    end
rescue => e
    raise e
end

需要注意的地方

  1. 一般,使用锁的时候和事务同时使用,所以 with_lock 是用的比较多的,而且尽量使用行锁而不是表锁。
  2. 另外,也注意异常的处理,需要使用那些会抛异常的方法;
  3. 对于乐观锁,还需要注意如果是前端操作频繁,那么还需要把 lock_version 写入到 form 表单中,否则起不到锁的作用,这里讲的很详细了

参考:https://ruby-china.org/topics/28963

附录:使用乐观锁的示例:

terminal

rails g migration add_lock_version_to_products lock_version:integer
rake db:migrate

products/_form.html.erb

<%= f.hidden_field :lock_version %>

products_controller.rb

class ProductionsController < ApplicationController
   def update
      # ... update code
   rescue ActiveRecord::StaleObjectError
      @production.reload.attributes = params[:production].reject do |attrb, value|
         attrb.to_sym == :lock_version
      end
      flash.now[:error] = "Another user has made a change to that record "+
         "since you accessed the edit form."
      render :edit, :status => :conflict
   end
end

相关文章

  • 锁的概述

    乐观锁与悲观锁 悲观锁 乐观锁和悲观锁的概念出自数据库,但在java并发包中也引入和类似的概念(乐观锁/悲观锁是一...

  • Mysql锁

    按照使用方式,锁分为: 悲观锁 乐观锁 乐观锁 概念就不细讲了,乐观锁和悲观锁的区别是乐观锁是假设在修改数据之前,...

  • 看完你就知道的乐观锁和悲观锁

    看完你就知道的乐观锁和悲观锁 Java 锁之乐观锁和悲观锁 [TOC] Java 按照锁的实现分为乐观锁和悲观锁,...

  • rails中乐观锁和悲观锁的使用

    MySQL乐观锁和悲观锁的介绍可以参考之前的一篇文章MySQL中的锁(行锁,表锁,乐观锁,悲观锁,共享锁,排他锁)...

  • 乐观锁和悲观锁

    参考来源 深入理解乐观锁与悲观锁 乐观锁的一种实现方式——CAS mysql乐观锁总结和实践 乐观锁和悲观锁 悲观...

  • 一文简介乐观锁和悲观锁

    悲观锁和乐观锁的概念 乐观锁和悲观锁在面试过程中是经常遇到的,那么什么是乐观锁什么是悲观锁呢?首先需要明确的是乐观...

  • 并发参数

    悲观锁与乐观锁 悲观锁 synchronized和ReentrantLock等独占锁就是悲观锁思想的实现乐观锁一般...

  • CAS 与原子操作

    乐观锁与悲观锁 锁可以从不同的角度分类。其中,乐观锁和悲观锁是一种分类方式。 乐观锁:乐观锁又称为“无锁”。乐观锁...

  • 史上最全 Java 中各种锁的介绍

    锁的分类介绍 乐观锁与悲观锁 锁的一种宏观分类是乐观锁与悲观锁。乐观锁与悲观锁并不是特定的指哪个锁(Java 中也...

  • 史上最全 Java 中各种锁的介绍

    锁的分类介绍 乐观锁与悲观锁 锁的一种宏观分类是乐观锁与悲观锁。乐观锁与悲观锁并不是特定的指哪个锁(Java 中也...

网友评论

    本文标题:rails中乐观锁和悲观锁的使用

    本文链接:https://www.haomeiwen.com/subject/babkkqtx.html