在Rails中迭代多个数据库的安全方法

Jim*_*ngs 5 ruby mysql connection multithreading ruby-on-rails

我在一台MySQL服务器上运行了几个Rails应用程序.它们都运行相同的应用程序,并且所有数据库都具有相同的架构,但每个数据库属于不同的客户.

从概念上讲,这就是我想要做的:

   Customer.all.each do |customer|
      connection.execute("use #{customer.database}")
      customer.do_some_complex_stuff_with_multiple_models
   end
Run Code Online (Sandbox Code Playgroud)

此方法不起作用,因为当在Web请求中运行此方法时,基础模型类将缓存来自A/R连接池的不同数据库连接.因此,我执行"use"语句的连接可能不是模型使用的连接,在这种情况下,它查询错误的数据库.

我阅读了Rails A/R代码(版本3.0.3),并提出了在循环中执行的代码,而不是"use"语句:

ActiveRecord::Base.clear_active_connections!
ActiveRecord::Base.establish_connection(each_customer_database_config)
Run Code Online (Sandbox Code Playgroud)

我相信连接池是每个线程的,所以看起来这会破坏连接池并仅为Web请求所在的一个线程重新建立它.但是,如果以某种方式共享连接,我没有看到,我不希望该代码在同一个应用程序中对其他活动Web请求造成严重破坏.

在运行的Web应用程序中这样做是否安全?有没有其他方法可以做到这一点?

Zim*_*bao 0

现在,ActiveRecord 中的连接可以是每个类级别的。它看起来是基于每个线程的,因为在 1.9 ruby​​ 线程之前,它的实现是使用进程而不是线程,但它可能不会持续很长时间。

但由于 AR 每个模型使用一个线程。您可以为您拥有的每个数据库创建不同的模拟模型。所以使用这个问题中给出的答案。

代码看起来像这样。(我没有测试过)

Customer.all.each do |customer|
     c_class = Class.new(ActiveRecord::Base)
     c_class.establish_connection(each_customer_database_config)
     c_class.table_name = customor.table_name()
     c_class.do_something_on_diff_models_using_cutomer_from_diff_conn(customer.id)
     c_class.clear_active_connections!
end
Run Code Online (Sandbox Code Playgroud)