2011-09-28 9 views
11

Nella mia classe di foto ho questa associazione.Rails come toccare l'oggetto Active Record senza bloccarlo?

belongs_to :user, :touch => true 

Un giorno ho ricevuto questa eccezione.

A ActiveRecord::StatementInvalid occurred in photos#update: 

Mysql::Error: Deadlock found when trying to get lock; try restarting transaction: 
UPDATE `users` SET `updated_at` = '2011-09-20 14:17:44' WHERE `users`.`id` = 6832 
production/ruby/1.8/gems/activerecord-3.0.10/lib/active_record/connection_adapters/abstract_adapter.rb:207:in `log' 

Cosa devo fare per evitare che si verifichino future eccezioni come questa? Vorrei che l'istruzione di aggiornamento mostrata nell'errore non utilizzasse il blocco se possibile. Non penso che utilizzare il blocco ottimistico funzionerà in questo caso, perché il blocco ottimistico probabilmente aumenterebbe un ActiveRecord :: StaleObjectError.

risposta

8

Questo è un problema che ho inciampato anche su me stesso.

Risposta breve: Non esiste un modo semplice per risolvere questo problema. Tutti gli touch sono avvolti nella stessa transazione, quindi il deadlock.

Risposta lunga: Sto supponendo che sia necessario toccare oggetti per invalidare alcune specie di cache (dipendenti). L'uso generalmente consigliato di touch funziona solo per un numero limitato di "relazioni". Per esempio. invalidare l'articolo quando il commento viene aggiornato.

La mia soluzione era la raccolta asincrona (che utilizza un lavoro sidekiq) di oggetti DB che devono essere invalidati. Ho scritto la mia logica di controllo per ciò che definisce quali (altri) oggetti devono essere invalidati quando un oggetto cambia. Per esempio. commento ==> articolo.

In questo modo abbiamo avuto un modo più dettagliato per invalidare gli oggetti dipendenti. Inoltre ho invalidato l'utilizzo di un Model.update_all che era molto più veloce della "catena del tocco". Ha risolto i nostri problemi di deadlock (e ha aggiunto verbosità e prestazioni alla nostra invalidazione della cache).

Suggerimento aggiuntivo: non utilizzare updated_at. È altamente discutibile se un oggetto DB è davvero cambiato perché un altro oggetto è cambiato. La sovrascrittura del modello cache_key consente di definire facilmente una chiave cache personalizzata come "#{id}-#{valid_from}". valid_from potrebbe essere un timestamp che definisci sui tuoi modelli (e che usi al posto di updated_at).

+0

Grazie per la risposta. Sono passati 2 anni e non sono del tutto sicuro del perché stavo usando il tatto. Invalidare la cache sembra una buona ragione. Ora utilizzo le spazzatrici per far scadere le voci della cache. http://guides.rubyonrails.org/caching_with_rails.html#sweepers. Non uso più il touch da nessuna parte. –

+0

Mi piace l'idea di valid_from, ma penso che sia necessario aggiungere anche il nome della classe nel cache_key, ad esempio [class]/[id] - [timestamp] come per http://signalvnoise.com/posts/3113- how-chiave-cache-scadenza-opere basate – iheggie

Problemi correlati