Rails如何构建MySQL语句?
我有以下代码在一个控制器内的heroku上运行, 间歇性地失败。 它应该对我很有用,但我必须遗漏一些东西。
@artist = Artist.find(params[:artist_id])
参数hash看起来像这样:
{"utf8"=>" ", "authenticity_token"=>"XXXXXXXXXXXXXXX", "password"=>"[FILTERED]", "commit"=>"Download", "action"=>"show", "controller"=>"albums", "artist_id"=>"62", "id"=>"157"}
我得到的错误看起来像这样:
ActiveRecord::StatementInvalid: Mysql::Error: : SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = ? LIMIT 1
注意WHERE
艺术家.
id = ?
声明的一部分? 它试图找到问号的ID。 含义Rails没有传入params[:artist_id]
,这显然是在params哈希中。 我完全失去了。
我在尝试以类似方式选择记录的不同页面上得到相同的错误。
我的环境:Heroku上的Cedar Stack( 这只发生在Heroku上),Ruby 1.9.3,Rails 3.2.8,托管在Amazon S3上的文件(虽然我怀疑它很重要),使用mysql
gem(不是mysql2
,它没有’完全工作),ClearDB MySQL数据库。
这是完整的痕迹 。
任何帮助将非常感激。
试试sql?
如果它只是这一个声明,并且它导致了生产问题,那么你现在可以省略查询生成器吗? 换句话说,就非常短期而言,只需自己编写SQL。 这会给你带来一些时间。
# All on one line: Artist.find_by_sql "SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = #{params[:artist_id].to_i} LIMIT 1"
ARel / MySQL解释?
Rails可以帮助解释MySQL正在尝试做什么:
Artist.find(params[:artist_id]).explain http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/
也许您可以发现成功与失败的查询之间存在某种差异,例如explain
如何使用索引或优化。
mysql2 gem?
你能尝试从mysql gem更改为mysql2 gem吗? 切换到mysql2 gem时会出现什么故障?
挥发性?
也许还有其它东西在运行中改变了params散列,所以你在打印它时会看到它,但它在查询运行时会改变吗?
收到params后立即尝试分配变量:
artist_id = params[:artist_id] ... whatever code here... @artist = Artist.find(artist_id)
不是params哈希?
你写道“意思是Rails没有通过params [:artist_id],这显然是在params hash中。” 我不认为这是问题 – 我希望你看到这个,因为Rails正在使用“?” 作为准备好的声明的占位符。
要找到答案,请运行@Mori建议的命令并进行比较; 他们应该是一样的。
Article.find(42).to_sql Article.find(params[:artist_id]).to_sql
准备好了吗?
当查询实际执行时,可能是准备好的语句缓存问题。
这是失败的代码 – 并且有一个很大的警告。
begin stmt.execute(*binds.map { |col, val| type_cast(val, col) }) rescue Mysql::Error => e # Older versions of MySQL leave the prepared statement in a bad # place when an error occurs. To support older mysql versions, we # need to close the statement and delete the statement from the # cache. stmt.close @statements.delete sql raise e end
尝试配置数据库以关闭预准备语句,看看是否有所作为。
在./config/database.yml
文件中:
production: adapter: mysql prepared_statements: false ...
准备好的陈述错误?
Rails忽略此设置可能存在问题。 如果你想了解更多关于它的信息,请参阅Jeremey Cole和Aaron的讨论和错误修复: https : //github.com/rails/rails/pull/7042
Heroku可能会忽略该设置。 这里有一种方法可以尝试通过修补prepared_statements设置来覆盖Heroku: https : //github.com/rails/rails/issues/5297
删除查询缓存?
尝试删除ActiveRecord QueryCache以查看是否有所不同:
config.middleware.delete ActiveRecord::QueryCache http://edgeguides.rubyonrails.org/configuring.html#configuring-middle
尝试postgres?
如果你可以尝试Postgres,那也可以清除它。 这对您来说可能不是一个长期的解决方案,但它会将问题与MySQL隔离开来。
MySQL语句显然是错误的,但是你提到的Ruby代码不会产生它。 这里有些问题,要么你使用不同的Ruby代码(可能是来自before_filter的代码),要么传递一个不同的参数(比如params [:artist_id] =“?”)。 看起来你使用嵌套资源,比如Artist has_many :albums
。 也许@artist变量在前一个动作中没有正确初始化,所以params [:artist_id]没有正确的值?