我在rails应用程序上遇到了一些错误,如下所示:
ActiveRecord::StatementInvalid: Mysql::Error: Lost connection to MySQL server during query: SELECT * FROM `actions` WHERE (`foo`.`id` = 16)
似乎正在发生的事情是mysql连接在超时后被关闭,并且rails没有注意到它为时已晚。
remedies I find appear to be在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
我正在列出此选项over this one visible here,因为此选项显然对交易不安全:
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
在避免这个恼人的错误的选项中,yaml文件中的重新连接选项似乎是最整洁的选项 - 但我很好奇;为什么你不会在数据库中默认将此值设置为true?
我宁愿不通过引起其他人的加载来解决一个问题。
谢谢,
答案 0 :(得分:13)
正如您在问题中所指出的,自动重新连接的一个可能的副作用(如果在每个语句级别完成)是因为它不是事务安全的。
MySQL documentation实际上明确指出自动重新连接功能会影响事务:
回滚任何活动事务并自动提交模式 复位。
未编写处理此问题的应用程序很容易破解。该文档还列出了自动重新连接功能引起的许多其他副作用,所有这些都可能导致未写入的应用程序预期行为无法正常运行或失败。
此外,如果与数据库的连接突然丢失,服务器可能无法正确释放连接所持有的锁,因此听起来应用程序在某些情况下可能会死锁:
如果连接断开,则为 可能会话关联 与服务器端的连接 如果服务器仍将运行 尚未检测到客户端 已不再连接。在这种情况下, 原件持有的任何锁 连接仍然属于那个 会话,所以你可能想要杀死它 调用mysql_kill()。
答案 1 :(得分:6)
来自Rails 2.3 release notes(强调我的):
4.8重新连接MySQL连接
MySQL在其连接中支持重新连接标志 - 如果设置为true,则客户端将尝试重新连接到服务器,然后在连接丢失的情况下放弃。您现在可以在database.yml中为MySQL连接设置
reconnect = true
,以便从Rails应用程序中获取此行为。默认值为false,因此现有应用程序的行为不会更改。