如何在Rails中与多个数据库并行建立连接?

时间:2017-10-30 23:45:20

标签: mysql ruby-on-rails database activerecord connection-pooling

上下文

我正在构建一个SaaS,用户可以在其中创建自己的网站(如Wix或SquareSpace)。 这就是幕后发生的事情:

  • 我的应用程序有其存储用户的主数据库
  • 当用户创建其网站时,会创建一个外部数据库来存储其数据
  • SQL文件在此外部数据库中运行以设置默认设置
  • 其他用户应同时创建其网站

方法

创建新数据库建立连接,请执行以下操作:

ActiveRecord::Base.connection.execute("CREATE DATABASE #{name}")
ActiveRecord::Base.establish_connection(<dynamic db data>)

然后我通过执行以下操作在db中执行sql 代码:

sql = File.read(sql_file.sql)
statements = sql.split(/;$/)
statements.pop
ActiveRecord::Base.transaction do
  statements.each do |statement|
    connection.execute(statement)
  end
end

然后我重新建立与主db的连接:

ActiveRecord::Base.establish_connection :production

问题

  1. 建立与动态数据库的连接使应用程序的主数据库暂时无法使用:
    • 用户A正在创建网站(建立动态数据库连接)
    • 用户B尝试访问其用户区域(需要应用程序的主数据库数据)
    • 应用程序抛出错误,因为它尝试检索app-main-db的数据(此时未建立连接)
  2. 如何在没有数据库冲突的情况下同时处理许多创建网站的用户?

    换句话说,我如何establish_connection并行使用多个数据库?

    注: 它与通过database.yml连接到多个数据库不同。此处的目标是同时连接和断开多个用户的动态创建的数据库

3 个答案:

答案 0 :(得分:1)

这个宝石可能有所帮助。但是,您可能需要重命名某些模型以使用外部数据库命名空间而不是ApplicationRecord

https://github.com/ankane/multiverse

答案 1 :(得分:1)

我承认这并不能回答你最初问题的核心,但IMO可能需要通过一个单独的操作来完成,比如通过队列以某种方式触发的纯SQL脚本。

您可以让您的rails应用程序删除&#34;创建消息&#34;到一个队列并有一个单独的服务,监视执行创建操作的队列,然后将带有信息的消息传递回队列。 rails应用程序监视队列中的这些,然后对信息执行某些操作。

更大的问题是解耦您的运营。这将帮助您顺利完成维护,缩放等工作。

FWIW这里是really cool website我最近发现了很多流行的排队服务。

答案 2 :(得分:0)

可能不是最好的方法,但可以通过在一个单独的ruby文件中调用创建数据库的外部脚本来实现:

  • lib 文件夹
  • 中创建create_database.rb文件
  • 将数据库创建脚本放在此文件中

    ActiveRecord::Base.connection.execute("CREATE DATABASE #{name}")
    ActiveRecord::Base.establish_connection(<dynamic db data>)
    
  • 使用Rails Runner执行

    rails runner lib/create_database.rb
    
  • 或使用系统,如果您想从控制器

    调用它
    system("rails runner lib/create_database.rb")
    

通过这种方式,您可以在不停止主数据库的情况下创建和访问多个数据库。

传递参数

您可以使用ARGV将参数传递给您的脚本:

rails runner lib/create_database.rb db_name

并使用ARGV[0]

在脚本中捕获它
name = ARGV[0]
puts name
> db_name