在什么情况下你希望Rails设置为不重新连接到MYSQL

Chr*_*ams 13 mysql ruby-on-rails

我在rails应用程序上遇到了一些错误,其中包括:

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

似乎正在发生的事情是mysql连接在超时后被关闭,并且rails没有注意到它为时已晚.

我找到 的补救措施似乎是在database.yaml中将reconnect标志设置为true,或者对于添加一些代码的任何数据库操作:

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
Run Code Online (Sandbox Code Playgroud)

我在此处列出了此选项,因为此选项显然对交易不安全:

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
Run Code Online (Sandbox Code Playgroud)

在避免这个烦人的错误的选项中,yaml文件中的重新连接选项似乎是最整洁的选项 - 但我很好奇; 为什么你不会在数据库中默认将此值设置为true?

我宁愿不通过引起其他人的加载来解决一个问题.

谢谢,

Mik*_*oss 13

正如您在问题中指出的那样,自动重新连接(如果在每个语句级别完成)的一个可能的副作用是它不是事务安全的.

MySQL 文档实际上明确指出自动重新连接功能会影响事务:

回滚任何活动事务并重置自动提交模式.

未写入处理此问题的应用程序很容易破解.该文档还列出了由自动重新连接功能引起的许多其他副作用,所有这些都可能导致未写入的应用程序预期行为无法正常运行或失败.

此外,如果与数据库的连接突然丢失,服务器可能无法正确释放连接所持有的锁,因此听起来应用程序在某些情况下可能会死锁:

如果连接断开,则如果服务器尚未检测到客户端不再连接,则与服务器端连接关联的会话可能仍在运行.在这种情况下,原始连接所持有的任何锁仍然属于该会话,因此您可能希望通过调用mysql_kill()来终止它.

  • 好的,现在我完全糊涂了.这告诉我,将`reconnect`设置为`true`可能是有害的,因为当它们不被认为是坏事时回滚的事务.避免这种状况的常用解决方法是什么? (2认同)

SFE*_*ley 6

从Rails 2.3发行说明(强调我的):

4.8重新连接MySQL连接

MySQL在其连接中支持重新连接标志 - 如果设置为true,则客户端将尝试重新连接到服务器,然后在连接丢失的情况下放弃.您现在可以reconnect = true在database.yml中设置MySQL连接,以便从Rails应用程序中获取此行为.默认值为false,因此现有应用程序的行为不会更改.