2012-09-27 21 views
5

Şu an işlemlerle uğraşıyorum ve şu senaryoyu taklit edemiyorum:Bu işlem neden ActiveRecord'da çalışmıyor?

Kullanıcı adı "johnny" ve tam adı "John Smith" olduğu düşünüldüğünde.

iki ray konsolları başlayıp bu sırada aşağıdaki komutları uygulayın:

Konsol A:

ActiveRecord::Base.transaction { user = User.find_by_username("foo"); sleep 10; user.update_attribute(:full_name, "#{user.full_name}-1"); } 

Konsol B:

ActiveRecord::Base.transaction { user = User.find_by_username("foo"); sleep 10; user.update_attribute(:full_name, "#{user.full_name}-2"); } 

Yani zamanlama şudur:

A okuru "John Smith"

B "John Smith"

bir yazar okur "John Smith-1"

B "John yazmaya başarısız olması benim veritabanı sınıfı işlem B'ye göre, "John Smith-2"

yazıyor Smith-2 "çünkü okuduğundan beri veriler değişti. Böylece işlem geri alınmalı ve A işlemi kazanmalıdır. Kullanıcı adının "John Smith-1" olmasını bekliyorum, ancak sonuç "John Smith-2".

Bunun neden olduğu veya beklenen davranışı nasıl alacağına dair herhangi bir fikir var mı? Ben işlem kilitleme ilgili değil anladığım kadarıyla

Tür Bildiğim kadarıyla

Nils

+0

Bağlantının yalıtım düzeyi olabilir. İyimser kilitleme ve imleç kararlılığı olmadığından emin olun. Ayrıca, ironik olarak, işlem yüzünden olabilir. Her iki blok da bir işlem içerisindeyse, teknik olarak, ikincinin ilk bitirene kadar * başlaması * ya da ikinci işlemin * ikinci işlemin * sanki ilk olmamış gibi davranması gerekir. * ikincisi ilk bitene kadar başlamadı. –

+0

Bunun harekete geçirici olduğunu düşündüğünüz nedir?Veritabanı komut satırından benzer bir görev gerçekleştirirseniz arabirim farklı sonuç mu? –

+0

@FrederickCheung Kullandığınız SQL'e bağlıdır. Eğer 'SELECT ... UPDATE İÇİN' ise, o zaman farklı olurdu. Hala OP'nin beklediği değil. Ama sonra kötümser bir kilitlenme olurdu: http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html –

cevap

4

bakımından, işlemin temel amacı atom değişiklikleri sağlamaktır. Örneğin, kontrol hesabınızdan para çekip tasarruf hesabınıza yatırdığınızda, hem INSERT'lerin başarılı olduğundan, hem de başarısız olduğundan veya tutarsız durumda bırakıldığınızdan emin olmanız gerekir. İhtiyacınız olan şey kilitleniyor, örn. http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html.

UPDATE: ACID, anladığım kadarıyla geri alma işlemini yapmak için kullanılmamıştır. Hata yoksa, her iki işlem de başarılı olur. Sonuç olarak elde ettiğiniz şey, izolasyona bağlı. SERIALIZABLE seviyesi kullanıldıysa, "John Smith-1-2" alırsınız, ancak InnoDB varsayılan olarak REPEATABLE READ düzeyini http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read kullanıyor demektir, yani SELECT kilitlenmiyorsa (User.find_by...) kayıt için kaydı kilitlemez ve A işleminin başlatıldığı anda oluşturulan anlık görüntüden orijinal sonuç (yani SELECT, A, SERIALIZABLE durumunda olduğu gibi A bitene kadar kilitlenmeyecektir).

GÜNCELLEME: Bu arada karamsar kilitleme için http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html kontrol edebilirsiniz.

+0

Her şeyden önce cevabınız için teşekkür ederiz. MySQL'in InnoDB-Transactions'larını bildiğim kadarıyla ACID (http://en.wikipedia.org/wiki/ACID) uyumludur. Açıklamanız "ben" i görmezden gelir, yalıtım, eşzamanlı işlemlerin sonucunun, sırayla yürütüldüğü ile aynı olduğu anlamına gelir; Yani soru şu: Neden ActiveRecord böyle çalışmıyor? – NilsHaldenwang

+0

Ah, açıklama için teşekkürler. – NilsHaldenwang