使用多数据库时Rails错误查询模型数据对应数据库的问题
Rails多数据库连接冲突问题解决
你遇到的问题根源是ActiveRecord::Base.establish_connection会修改Rails全局的默认数据库连接。第一次请求时,你先通过Word.find_by使用了默认开发库的连接,之后调用establish_connection切换到了test数据库;但Rails的连接池会复用连接,刷新页面时,Word.find_by会复用已经切换到test库的连接,自然找不到words表。
以下是几种可行的解决方案:
方案1:临时切换后恢复默认连接
在操作完外部数据库后,手动将全局连接切回原来的配置,避免后续请求复用错误连接。
修改后的控制器代码:
class TestController < ApplicationController def test itemOne = Word.find_by(name:"Cat") @textOne = itemOne.txt # 保存原连接配置 original_config = ActiveRecord::Base.connection_config # 切换到外部数据库执行操作 con = ActiveRecord::Base.establish_connection(adapter: 'mysql2', encoding: 'utf8mb4', username: 'root', password: '<omitted>', host: 'localhost', database: 'test').connection @textTwo = con.execute('select txt from extst where name="Bob"').to_a[0][0] # 切回原数据库连接 ActiveRecord::Base.establish_connection(original_config) end end
这种方式简单直接,但高并发场景下可能出现连接冲突,适合低并发的临时需求。
方案2:创建专用外部数据库模型(推荐)
这是Rails多数据库场景的标准做法,通过抽象模型隔离不同数据库的连接,完全避免全局连接修改。
- 在
config/database.yml中添加外部数据库配置:
test_ext: adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: <omitted> host: localhost database: test
- 创建抽象基类模型
app/models/test_ext_base.rb:
class TestExtBase < ActiveRecord::Base self.abstract_class = true establish_connection :test_ext end
- 若需要用ActiveRecord操作外部表,创建对应模型
app/models/extst.rb:
class Extst < TestExtBase self.table_name = 'extst' # 指定外部数据库中的表名 end
- 修改控制器代码,直接使用模型或基类连接:
class TestController < ApplicationController def test itemOne = Word.find_by(name:"Cat") @textOne = itemOne.txt # 方式1:通过模型查询(推荐,符合Rails规范) @textTwo = Extst.find_by(name: "Bob").txt # 方式2:直接用基类连接执行原生SQL # @textTwo = TestExtBase.connection.execute('select txt from extst where name="Bob"').to_a[0][0] end end
方案3:直接获取指定配置的连接
如果只是偶尔执行原生SQL,也可以直接从连接池获取指定配置的连接,不修改全局连接:
class TestController < ApplicationController def test itemOne = Word.find_by(name:"Cat") @textOne = itemOne.txt # 从连接池获取指定配置的连接 ext_config = Rails.configuration.database_configuration['test_ext'] @textTwo = ActiveRecord::Base.connection_pool.with_connection(ext_config) do |conn| conn.execute('select txt from extst where name="Bob"').to_a[0][0] end end end
注意需要先在database.yml中配置test_ext。
内容的提问来源于stack exchange,提问作者Programmer S
相关产品推荐
相关产品推荐

