Question

En quelque sorte, je les reçois toujours le vendredi.

Ma question précédente concernait le même problème, mais je peux maintenant préciser un peu les choses:

J'ai joué avec ça toute la journée, essayant de lui donner un sens. J'ai une table avec une colonne lock_version, spécifiée ainsi:

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

Et je fais quelque chose comme ça:

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

Je vérifie ensuite que les premier et second font référence au même objet - leurs identifiants sont identiques et je vois cette ligne dans la base de données à l'aide de l'outil de ligne de commande mysql.

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

pas de problème jusqu'à présent. J'ai correctement une exception ActiveRecord :: StaleObjectError. TOUTEFOIS :

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

... et rien ne se passe. Il s'avère que le seul comportement correct (exception levée) est lorsque lock_version est égal à 0 pour le premier et le deuxième. Après la première sauvegarde, il ne s'agit plus jamais de 0. Qu'est-ce qui se passe avec ça?

J'utilise ruby ??1.8.6 et enregistrement actif 2.2.2

Merci ...

Était-ce utile?

La solution

lorsque vous appelez first.save pour la deuxième fois, la valeur de some_attribute_field est déjà égale à "first", activerecord le sait, de sorte qu'il n'est pas mis à jour dans la base de données. lock_version n'est pas incrémenté. La deuxième sauvegarde fonctionne, car la base de données n’a jamais été modifiée avec la "première".

Essayez de remplacer le "premier" par la valeur du deuxième test. afin qu'il soit différent de ce qui est dans la base de données.

Autres conseils

Je ne suis pas un gars de Ruby, mais le verrouillage optimiste m'est familier, je vais donc essayer de vous aider à le déboguer.

Je présume que la deuxième sauvegarde met réellement à jour la base de données. Si les deux objets ont différents lock_version ET si lock_version est utilisé dans UPDATE, ce n'est tout simplement pas possible (UPDATE ne mettrait à jour aucune ligne). Nous n’avons donc que deux alternatives:

  • version_lock n'est pas utilisé dans l'instruction UPDATE ou utilisé de manière incorrecte
  • les deux objets ont en quelque sorte la même lock_version

( en fait, il existe une troisième alternative: les deux save () sont dans leur propre transaction, mais je pense que vous avez AUTOCOMMIT = true )

Pouvez-vous afficher les instructions SQL réelles? La déclaration de mise à jour doit ressembler à quelque chose comme

... WHERE JOB_ID=123 AND LOCK_VERSION=8

Lorsque vous aurez les requêtes à portée de main, il sera beaucoup plus facile de comprendre ce qui se passe.

P.S. et encore un: dans votre exemple, dans un autre sujet, vous avez cet objet:

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

L'appel de sauvegarde () peut être ignoré par conteneur si les propriétés ne sont pas modifiées par rapport au temps de chargement. Je ne sais pas si ActiveRecord a cette optimisation ou non. Mais si tel est le cas, la deuxième sauvegarde () est ignorée et le verrouillage optimiste n’a aucune chance de s’engager.

Comme l'a dit Vladimir, votre code test / exemple est un peu imparfait. Le premier ne sera pas stocké dans la base de données lors de la deuxième sauvegarde! () Car aucun attribut n'a changé. Voir l'exemple suivant:

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

cela produit:

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

L'utilisation de votre exemple dans la version 2.3.2 de rails fonctionne comme il se doit avec une exception d'objet obsolète lorsque la seconde est enregistrée (les deux fois!)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top