Ruby on Rails 5.2 - ActiveRecord::Locking::Pessimistic

मॉड्यूल ActiveRecord :: लॉकिंग :: निराशावादी




ruby

मॉड्यूल ActiveRecord :: लॉकिंग :: निराशावादी

Locking::Pessimistic चयन के लिए पंक्ति-स्तर लॉकिंग के लिए समर्थन प्रदान करता है ... अद्यतन और अन्य लॉक प्रकारों के लिए।

चेन ActiveRecord::Base#find ActiveRecord::QueryMethods#lock चयनित ActiveRecord::QueryMethods#lock पर एक विशेष लॉक प्राप्त करने के लिए लॉक:

# select * from accounts where id=1 for update
Account.lock.find(1)

अपने स्वयं के डेटाबेस-विशिष्ट लॉकिंग क्लॉज जैसे 'LOCK IN SHARE MODE' या 'UPDATE NOWAIT के लिए' का उपयोग करने के लिए lock('some locking clause') को कॉल करें। उदाहरण:

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

आप ActiveRecord::Base#lock! का भी उपयोग कर सकते हैं ActiveRecord::Base#lock! आईडी द्वारा एक रिकॉर्ड को लॉक करने की विधि। यह बेहतर हो सकता है अगर आपको हर पंक्ति को लॉक करने की आवश्यकता नहीं है। उदाहरण:

Account.transaction do
  # select * from accounts where ...
  accounts = Account.where(...)
  account1 = accounts.detect { |account| ... }
  account2 = accounts.detect { |account| ... }
  # select * from accounts where id=? for update
  account1.lock!
  account2.lock!
  account1.balance -= 100
  account1.save!
  account2.balance += 100
  account2.save!
end

आप एक लेनदेन शुरू कर सकते हैं और एक ब्लॉक के साथ with_lock कॉल करके एक बार में लॉक प्राप्त कर सकते हैं। ब्लॉक को एक लेनदेन के भीतर से बुलाया जाता है, ऑब्जेक्ट पहले से ही लॉक है। उदाहरण:

account = Account.first
account.with_lock do
  # This block is called within a transaction,
  # account is already locked.
  account.balance -= 100
  account.save!
end

पंक्ति-लॉकिंग पर डेटाबेस-विशिष्ट जानकारी:

MySQL: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
PostgreSQL: https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE

सार्वजनिक प्रवृत्ति के तरीके

ताला! (lock = true) स्रोत दिखाएं
# File activerecord/lib/active_record/locking/pessimistic.rb, line 63
      def lock!(lock = true)
        if persisted?
          if has_changes_to_save?
            raise(<<-MSG.squish)
              Locking a record with unpersisted changes is not supported. Use
              `save` to persist the changes, or `reload` to discard them
              explicitly.
            MSG
          end

          reload(lock: lock)
        end
        self
      end

इस रिकॉर्ड पर एक पंक्ति लॉक प्राप्त करें। अनुरोधित ताला प्राप्त करने के लिए रिकॉर्ड को पुनः लोड करें। एक एसक्यूएल लॉकिंग क्लॉज को सेलेक्ट स्टेटमेंट के अंत में पास करें या "फॉर अपडेट" (डिफ़ॉल्ट, एक विशेष पंक्ति लॉक) के लिए सही पास करें। बंद रिकॉर्ड लौटाता है।

with_lock (लॉक = सत्य) {|| ...} स्रोत दिखाएं
# File activerecord/lib/active_record/locking/pessimistic.rb, line 81
def with_lock(lock = true)
  transaction do
    lock!(lock)
    yield
  end
end

पैदावार में पारित ब्लॉक को लपेटता है, उपज से पहले ऑब्जेक्ट को लॉक करता है। आप एसक्यूएल लॉकिंग क्लॉज को तर्क के रूप में पास कर सकते हैं ( lock! देखें lock! )।