2009-10-08 12 views
12

que estoy experimentando algunos errores en una aplicación de rieles, a lo largo de las líneas de:¿En qué circunstancias le gustaría rieles para ser configurado para no volver a conectar a MySQL

ActiveRecord::StatementInvalid: Mysql::Error: Lost connection to MySQL server during query: SELECT * FROM `actions` WHERE (`foo`.`id` = 16) 

Lo que parece estar sucediendo es que MySQL la conexión se cierra después de un tiempo de espera, y los rieles no se notan hasta que es demasiado tarde.

El remedies I findappear to be para establecer el indicador de reconexión en true en database.yaml, o por cualquier acción de base de datos añadiendo un poco de código de este modo:

def some_database_operation 
    begin 
    Account.find(1) 
    # or some other database operations here... 
    rescue ActiveRecord::StatementInvalid 
    ActiveRecord::Base.connection.reconnect! 
    unless @already_retried 
     @already_retried = true 
     retry 
    end 
    raise 
    else 
    @already_retried = false 
    end 
end 
end 

estoy lista over this one visible here esta opción, ya que esta opción es aparentemente inseguro para las transacciones:

ActiveRecord::ConnectionAdapters::MysqlAdapter.module_eval do 
    def execute_with_retry_once(sql, name = nil) 
    retried = false 
    begin 
     execute_without_retry_once(sql, name) 
    rescue ActiveRecord::StatementInvalid => exception 
     ActiveRecord::Base.logger.info "#{exception}, retried? #{retried}" 

     # Our database connection has gone away, reconnect and retry this method 
     reconnect! 
     unless retried 
     retried = true 
     retry 
     end 
    end 
    end 

    alias_method_chain :execute, :retry_once 
end 

de las opciones para evitar este error molesto, la opción de reconexión en el archivo yaml parece por el momento la opción más limpio - pero tengo curiosidad; ¿Por qué no establecería este valor como verdadero de forma predeterminada en su base de datos?

Prefiero no resolver un problema causando una carga de otros más adelante en la línea.

Gracias,

Respuesta

12

Como usted ha señalado en la pregunta, un posible efecto secundario de volver a conectar automáticamente (si se hace a un nivel por declaración), es que no es transaccionales.

El MySQL documentation, de hecho, afirma explícitamente que la función de auto-reconexión afecta a las transacciones:

cualquier transacción activa se deshacen y el modo de confirmación automática está reinicio.

Las aplicaciones que no están escritas para resolver esto podrían romperse fácilmente. La documentación también enumera una serie de otros efectos secundarios causados ​​por la función de reconexión automática, todos los cuales podrían causar que las aplicaciones no escritas prevean que el comportamiento no funcione correctamente o falle.

Además, si de repente se pierde la conexión a la base de datos, el servidor podría no liberar adecuadamente cerraduras que estaban en poder de la conexión, por lo que suena como una aplicación podría estancamiento en algunos casos:

Si la conexión cae, es posible que la sesión asociada con la conexión en el lado del servidor seguirá ejecutándose si el servidor aún no ha detectado que el cliente ya no está conectado. En este caso, cualquier bloqueo realizado por la conexión original todavía pertenecen a esa sesión , por lo que puede acabar con él por llamando mysql_kill().

+2

Bien, ahora estoy totalmente confundido. Esto me sugiere que configurar 'reconectar' a 'verdadero' podría ser perjudicial, porque las transacciones que se retrotraen cuando no se supone suenan como algo malo. ¿Cuál es la solución habitual para evitar este estado de cosas? –

+0

La solución es asegurarse de que sus transacciones sean "atómicas", es decir, si pierde la conexión y se vuelve a conectar, se debe volver a intentar toda la transacción, no solo una declaración única dentro de la transacción. No estoy seguro de cómo funciona esto en Rails, pero supongo que una solución sería poner la transacción en un procedimiento almacenado: en el código de Rails, se ejecuta una única instrucción SQL para ejecutar el procedimiento almacenado, y luego si se reconecta automáticamente. , toda la transacción comienza desde el principio. –

+0

OTOH, si no está usando transacciones, entonces usar la función de reconexión automática probablemente sea un problema menor. –

5

Desde el (el énfasis es mío) Rails 2.3 release notes:

4.8 Reconexión conexiones MySQL

MySQL soporta una bandera de reconexión en sus conexiones - Si es verdadero, entonces el el cliente intentará volver a conectarse al servidor antes de darse por vencido en caso de una conexión perdida. Ahora puede establecer reconnect = true para sus conexiones MySQL en database.yml para obtener este comportamiento de una aplicación de Rails. El valor predeterminado es falso, , por lo que el comportamiento de las aplicaciones existentes no cambia.

Cuestiones relacionadas