Domanda

In qualche modo, ricevo sempre questi di venerdì.

La mia domanda precedente riguardava lo stesso problema, ma ora posso restringere un po 'le cose:

Ci ho giocato tutto il giorno, cercando di dargli un senso. Ho una tabella con una colonna lock_version, specificata così:

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

E faccio qualcosa del genere:

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

Verifico quindi che il primo e il secondo si riferiscano allo stesso oggetto: i loro ID sono gli stessi e vedo quella riga nel database usando lo strumento da riga di comando mysql.

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

nessun problema finora. Ottengo correttamente un'eccezione ActiveRecord :: StaleObjectError. TUTTAVIA :

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

... e non succede nulla. Si scopre che l'unica volta in cui ottengo un comportamento corretto (eccezione generata) è quando il primo e il secondo hanno una lock_version di 0. Dopo il primo salvataggio, tuttavia, non è MAI di nuovo 0. Cosa diavolo succede con questo?

Sto usando ruby ??1.8.6 e il record attivo 2.2.2

Grazie ...

È stato utile?

Soluzione

quando chiami first.save la seconda volta il valore di some_attribute_field è già uguale a " first " ;, activerecord lo sa quindi non si aggiorna nel db a lock_version non viene incrementato. Il secondo salvataggio funziona poiché il db non è mai stato modificato con il "primo".

Prova a cambiare il valore nel secondo test in qualcosa di diverso da "primo" in modo che sia diverso da ciò che è nel db.

Altri suggerimenti

Non sono un tipo Ruby, ma il blocco ottimistico mi è familiare, quindi cercherò di aiutarti a eseguire il debug.

Presumo che il secondo salvataggio aggiorni effettivamente il database. Se entrambi gli oggetti hanno lock_version diversi E lock_version viene utilizzato in UPDATE, semplicemente non è possibile (UPDATE aggiorna zero righe). Quindi, abbiamo solo due alternative:

  • lock_version non viene utilizzato nell'istruzione UPDATE o utilizzato in modo errato
  • entrambi gli oggetti hanno ottenuto la stessa lock_version in qualche modo

( in realtà, esiste una terza alternativa: entrambi save () sono nella propria transazione, ma ritengo che tu abbia AUTOCOMMIT = true )

Puoi rendere visibili le effettive istruzioni SQL? La dichiarazione di aggiornamento dovrebbe essere simile a

... WHERE JOB_ID=123 AND LOCK_VERSION=8

Quando avrai a portata di mano le domande, sarebbe molto più semplice capire cosa sta succedendo.

P.S. e ancora uno: nel tuo esempio in un altro argomento hai questo oggetto:

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

La chiamata save () può essere ignorata dal contenitore se le proprietà non vengono modificate rispetto al tempo di caricamento. Non so se ActiveRecord abbia questa ottimizzazione o no. Ma se lo fa, il secondo save () viene ignorato e il blocco ottimistico non ha la possibilità di entrare.

Come ha detto Vladimir, il tuo codice di test / esempio è un po 'difettoso. Il primo non viene memorizzato nella base di dati durante il secondo salvataggio! () Perché nessun attributo è stato modificato. Vedi il seguente esempio:

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

questo produce:

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

L'uso del tuo esempio nella versione 2.3.2 di rotaie funziona come dovrebbe con un'eccezione di oggetto obsoleto quando il secondo viene salvato (entrambe le volte!)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top