ran*_*its 12 ruby sql ruby-on-rails sidekiq ruby-on-rails-4
我有一个Rails 4应用程序,我与它一起使用sidekiq
来运行异步作业.我通常在我的Rails应用程序之外运行的一个作业是一大堆复杂的SQL查询,它们无法真正由ActiveRecord建模.这组SQL查询与我的Rails应用程序的连接是,它应该在我的一个控制器操作被调用时执行.
理想情况下,我会从控制器中的Rails应用程序中为Sidekiq排队,继续运行查询.现在它们存储在一个外部文件中,我不完全确定Rails运行所述SQL的最佳方法是什么.
任何解决方案都很受欢
Jan*_*rik 12
我同意Sharagoz,如果您只需要运行特定查询,最好的方法是将查询字符串直接发送到连接中,例如:
ActiveRecord::Base.connection.execute(File.read("myquery.sql"))
Run Code Online (Sandbox Code Playgroud)
如果查询不是静态的,你必须编写它,我会使用Arel,它已经存在于Rails 4.x中:
https://github.com/rails/arel
Run Code Online (Sandbox Code Playgroud)
inf*_*sed 10
你没有说你正在使用什么数据库,所以我将假设MySQL.
您可以使用mysql
二进制文件来完成工作:
result = `mysql -u #{user} --password #{password} #{database} < #{huge_sql_filename}`
Run Code Online (Sandbox Code Playgroud)
或者使用ActiveRecord::Base.connection.execute(File.read("huge.sql"))
,但如果SQL文件中有多个SQL语句,它将无法开箱即用.
为了运行多个语句,您需要创建一个初始化程序,ActiveRecord::Base.mysql2_connection
用于修补程序以允许设置MySQL的CLIENT_MULTI_STATEMENTS和CLIENT_MULTI_RESULTS标志.
创建一个新的初始化程序 config/initializers/mysql2.rb
module ActiveRecord
class Base
# Overriding ActiveRecord::Base.mysql2_connection
# method to allow passing options from database.yml
#
# Example of database.yml
#
# login: &login
# socket: /tmp/mysql.sock
# adapter: mysql2
# host: localhost
# encoding: utf8
# flags: 131072
#
# @param [Hash] config hash that you define in your
# database.yml
# @return [Mysql2Adapter] new MySQL adapter object
#
def self.mysql2_connection(config)
config[:username] = 'root' if config[:username].nil?
if Mysql2::Client.const_defined? :FOUND_ROWS
config[:flags] = config[:flags] ? config[:flags] | Mysql2::Client::FOUND_ROWS : Mysql2::Client::FOUND_ROWS
end
client = Mysql2::Client.new(config.symbolize_keys)
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
end
end
end
Run Code Online (Sandbox Code Playgroud)
然后更新config/database.yml
以添加标志:
development:
adapter: mysql2
database: app_development
username: user
password: password
flags: <%= 65536 | 131072 %>
Run Code Online (Sandbox Code Playgroud)
我刚刚在Rails 4.1上对它进行了测试,效果很好.
资料来源:http://www.spectator.in/2011/03/12/rails2-mysql2-and-stored-procedures/
正如其他人所概述的那样,执行一个查询非常简单
ActiveRecord::Base.connection.execute("SELECT COUNT(*) FROM users")
Run Code Online (Sandbox Code Playgroud)
您正在谈论多个查询的20.000行sql脚本.假设您在某种程度上控制了该文件,您可以从中提取单个查询.
script = Rails.root.join("lib").join("script.sql").read # ah, Pathnames
# this needs to match the delimiter of your queries
STATEMENT_SEPARATOR = ";\n\n"
ActiveRecord::Base.transaction do
script.split(STATEMENT_SEPARATOR).each do |stmt|
ActiveRecord::Base.connection.execute(stmt)
end
end
Run Code Online (Sandbox Code Playgroud)
如果你很幸运,那么查询分隔符可能是"; \n \n",但这当然取决于你的脚本.我们在另一个例子中有"\ x0"作为分隔符.关键是您将脚本拆分为查询以将它们发送到数据库.我将它包装在一个事务中,让数据库知道有多个语句.在发送脚本查询时没有引发异常时,块提交.
如果您没有控制脚本文件,请开始与控制它的人交谈,以获得可靠的分隔符.如果它不在你的控制范围内而且你无法与控制它的那个人交谈,我猜你也不会执行它:-)
.
UPDATE
这是解决此问题的通用方法.对于PostgreSQL,您不需要手动拆分语句.你可以一次性发送它们execute
.对于MySQL,似乎有解决方案将适配器转换为CLIENT_MULTI_STATEMENTS模式.
如果要通过活动记录执行原始SQL,可以使用此API:
ActiveRecord::Base.connection.execute("SELECT COUNT(*) FROM users")
归档时间: |
|
查看次数: |
5564 次 |
最近记录: |