Pregunta

De alguna manera, siempre los recibo los viernes.

Mi pregunta anterior era sobre el mismo problema, pero ahora puedo reducir un poco las cosas:

He estado jugando con esto todo el día, tratando de darle sentido. Tengo una tabla con una columna lock_version, especificada así:

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

Y hago algo como esto:

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

Luego verifico que el primero y el segundo hacen referencia al mismo objeto: sus identificadores son los mismos y veo esa fila en la base de datos utilizando la herramienta de línea de comandos mysql.

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

no hay problema hasta ahora. Obtuve correctamente una excepción ActiveRecord :: StaleObjectError. SIN EMBARGO :

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

... y no pasa nada. Resulta que la única vez que obtengo el comportamiento correcto (excepción lanzada) es cuando primero y segundo tienen una versión de bloqueo de 0. Después del primer guardado, sin embargo, NUNCA vuelve a ser 0. ¿Qué diablos pasa con esto?

Estoy usando ruby ??1.8.6 y el registro activo 2.2.2

Gracias ...

¿Fue útil?

Solución

cuando llamas first.save la segunda vez, el valor de some_attribute_field ya es igual a " first " ;, activerecord lo sabe, por lo que no se actualiza en la base de datos para que lock_version no se incremente. La segunda operación de guardar funciona ya que nunca se cambió la db con la " primera " ;.

Intente cambiar el valor en la segunda prueba a algo distinto de " primera " para que sea diferente de lo que hay en la base de datos.

Otros consejos

No soy un chico Ruby, pero el bloqueo optimista me resulta familiar, así que intentaré ayudarte a depurarlo.

Supongo que el segundo guardado realmente actualiza la base de datos. Si ambos objetos tienen diferente lock_version Y lock_version se usa en UPDATE, simplemente no es posible (UPDATE actualizaría cero filas). Entonces, solo tenemos dos alternativas:

  • lock_version no se usa en la instrucción UPDATE o se usa incorrectamente
  • ambos objetos obtuvieron la misma versión de bloqueo de alguna manera

( en realidad, hay una tercera alternativa: ambos save () están en su propia transacción, pero siento que tienes AUTOCOMMIT = true )

¿Puedes hacer visibles las sentencias de SQL reales? La declaración de actualización debería leer algo así como

... WHERE JOB_ID=123 AND LOCK_VERSION=8

Cuando tenga a mano las consultas, será mucho más fácil entender lo que está sucediendo.

P.S. y uno más: en su ejemplo en otro tema tiene este objeto:

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

El contenedor puede ignorar la llamada save () si las propiedades no cambian en comparación con el tiempo de carga. Sin embargo, no sé si ActiveRecord tiene esta optimización o no. Pero si lo hace, entonces se ignora el segundo save (), y el bloqueo optimista no tiene la oportunidad de entrar en acción.

Como dijo Vladimir, su código de prueba / ejemplo es un poco defectuoso. ¡Primero no se almacena en la base de datos durante el segundo guardado! () Porque ningún atributo ha cambiado. Vea el siguiente ejemplo:

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

esto produce:

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

Usar su ejemplo en la versión 2.3.2 de rails funciona como debería con una excepción de objeto obsoleto cuando se guarda el segundo (¡ambas veces!)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top