2012-07-26 21 views
9

? Necesito ejecutar SQL sin formato en mi aplicación Rails. La consulta generará una confirmación implícita si se realiza dentro de una transacción. Estamos utilizando MySQL con InnoDB y la consulta incluirá p. Ej. crear mesa.¿Cómo puedo ejecutar una operación de base de datos fuera de una transacción en Rails/ActiveRecord

La ejecución de la consulta con ActiveRecord::Base.connection.execute desencadena el compromiso de implict que es un problema.

Parece que solo necesito una conexión separada para realizar mis consultas. ¿Puede ActiveRecord proporcionar esto? He visto discusiones sobre la conexión a múltiples bases de datos pero no múltiples conexiones a la misma base de datos.

Una solución no tiene que involucrar ActiveRecord si hay una mejor manera.

Nuestra versión de Rails y ActiveRecord es 3.2.3.

Respuesta

16

conexiones de base de datos se realizan sobre una base por hilo (esto es básicamente necesario para la seguridad de los subprocesos), que se puede utilizar a su ventaja: sólo hay que ejecutar el código en un hilo separado, por ejemplo

ActiveRecord::Base.transaction do 
    # ... 
    Thread.new do 
    ActiveRecord::Base.connection.execute "..." # in a new connection 
    end.join 
end 

Como de rails 4, activerecord ya no recoge las conexiones creadas de esta manera automáticamente. Para evitar fugas de conexiones, debe devolverlas al grupo. Como sugiere Matt Connelly, la forma más sencilla de hacerlo es utilizar el método with_connection que comprobará la conexión de nuevo al final del bloque, por ejemplo

Thread.new do 
    ActiveRecord::Base.connection_pool.with_connection do 
    ... 
    end 
end 
+0

Creo que entendiste mejor el problema :) – PriteshJ

+1

¡Asegúrate de devolver la conexión al grupo de conexiones cuando hayas terminado! –

+0

¡Buena llamada! - La respuesta no estaba actualizada. –

1

DDL y algunos más consultas fuego COMMIT implícito por lo que no se pueden revertir según la documentación de MySQL

http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html

Estos implícitamente terminar cualquier transacción activa en la sesión actual, como si se hubiera hecho un COMMIT antes de ejecutar la declaración.

Si no hay tales consultas intermedias, puede usar la función SAVEPOINT. (This does not work with DDL statements)

Hay una opción de registro en activo que ayuda a crear las transacciones sub que usa los puntos de almacenamiento

ActiveRecord::Base.transaction do 
    # ... 
    ActiveRecord::Base.transaction(:requires_new => true) do #creates save point 
     # perform task 
     # if error occurs rollbacks only till the save point. 
    end 
    end 

Verificar rails doc para más detalles.

+0

El autor está hablando de las declaraciones que siempre va a cometer implícitamente una transacción (por ejemplo, alterar la tabla) –

+0

@FrederickCheung, partir de la pregunta "ActiveRecord :: Base.connection.execute desencadena el compromiso de implict que es un problema ". me hace creer que quiere controlar explícitamente la transacción. Corrígeme si estoy equivocado – PriteshJ

2

Es importante que si se utiliza una conexión en un hilo que devuelve la conexión al grupo de conexiones cuando termina. La forma más sencilla de hacerlo es la siguiente:

Thread.new do 
    ActiveRecord::Base.connection_pool.with_connection do |connection| 
    connection.execute "..." 
    # ensures the connection is returned to the pool when the thread is done.   
    end 
end.join 
Cuestiones relacionadas