سؤال

بطريقة ما ، أنا دائما أحصل على هذه يوم الجمعة.

كان سؤالي السابق يتعلق بنفس المشكلة ، لكن يمكنني الآن تضييق الأشياء قليلاً:

لقد كنت ألعب مع هذا طوال اليوم ، في محاولة لفهم ذلك. لدي جدول مع colum lock_version ، محدد هكذا:

add_column :jobs, :lock_version, :integer, :default=>0

وأنا أفعل شيئًا كهذا:

foo = job.create!
first = Job.find(foo.id)
second = Job.find(foo.id)

أتحقق بعد ذلك من أن المشاركة الأولى والثانية في نفس الكائن - معرفاتهم هي نفسها وأرى هذا الصف في قاعدة البيانات باستخدام أداة سطر الأوامر MySQL.

first.some_attribute_field = 'first'
second.some_attribute_field = 'second'
first.save
second.save

لا مشكلة حتى الآن. أحصل على استثناء ActivereCord بشكل صحيح :: StaleObjecterror. ومع ذلك:

first = Job.find(foo.id)
second = Job.find(foo.id)
first.some_attribute_field = 'first'
second.some_attribute_field = 'second'
first.save
second.save

... ولا شيء يحدث. اتضح أن المرة الوحيدة التي أحصل فيها على سلوك (استثناء استثناء) صحيح هو عندما يكون للمرة الأولى والثانية قفلًا. ماذا على الأرض مع هذا؟

أنا أستخدم Ruby 1.8.6 والسجل النشط 2.2.2

شكرًا...

هل كانت مفيدة؟

المحلول

عندما تتصل أولاً. في المرة الثانية ، تكون قيمة Some_attribute_field مساوية بالفعل لـ "First" ، ActivereCord يعرف هذا حتى لا يتم تحديثها في DB إلى Lock_version لا يتم زيادة. يعمل الحفظ الثاني حيث لم يتغير DB مع "الأول".

حاول تغيير القيمة في الاختبار الثاني إلى شيء آخر غير "الأول" بحيث يختلف عن ما هو موجود في DB.

نصائح أخرى

أنا لست رجلًا روبيًا ، لكن القفل المتفائل مألوف بالنسبة لي ، لذلك سأحاول مساعدتك في تصحيحه.

أفترض أن Second Save يقوم بالفعل بتحديث قاعدة البيانات. إذا كان كلا الكائنين يحتويان على LOCK_VERSION واستخدام LOCK_VERVENT في التحديث ، فسيكون ذلك ببساطة غير ممكن (سيتم تحديث الصفوف الصفرية). لذلك ، لدينا فقط بديلين:

  • لا يتم استخدام lock_version في عبارة التحديث أو استخدامه بشكل غير صحيح
  • حصل كلا الكائنين على نفس Lock_version بطريقة ما

(في الواقع ، هناك بديل ثالث: كلاهما Save () في معاملتهما الخاصة ، لكنني أشعر أن لديك AutoCommit = صحيح)

هل يمكنك جعل عبارات SQL الفعلية مرئية؟ يجب أن تقرأ عبارة التحديث شيئًا مثل

... WHERE JOB_ID=123 AND LOCK_VERSION=8

عندما يكون لديك استعلامات فعليًا ، سيكون من الأسهل بكثير فهم ما يجري.

ملاحظة وواحدة أخرى: في مثالك في موضوع آخر لديك هذا الكائن:

#<Job id: 323, lock: 8, worker_host: "second">

قد يتم تجاهل مكالمة SAVE () بواسطة الحاوية إذا لم يتم تغيير الخصائص مقارنة بوقت التحميل. لا أعرف ما إذا كان ActivereCord لديه هذا التحسين أم لا. ولكن إذا كان الأمر كذلك ، فسيتم تجاهل Save () الثاني ، ولم يكن لدى القفل المتفائل فرصة للركل.

كما قال فلاديمير ، فإن رمز الاختبار/المثال الخاص بك معيب بعض الشيء. أولاً ، لا يتم تخزينها في قاعدة DateBase أثناء الحفظ الثاني! () لأنه لم تتغير أي سمات. انظر المثال التالي:

foo = Account.create!

first = Account.find(foo.id)
first.cash = 100
first.save!


first = Account.find(foo.id)
first.cash = 100

puts "First lock before " + first.lock_version.to_s
first.save!
puts "First lock after " + first.lock_version.to_s

هذا ينتج:

% script/runner another_tester.rb                               
First lock before 1
First lock after 1

باستخدام مثالك في الإصدار 2.3.2 من Rails يعمل كما ينبغي مع استثناء كائن قديم عند حفظ الثانية (في كلتا الحالتين!)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top