Rails 两个 Rails 项目共用一个数据库,请教成熟的解决方案

ery · 2012年11月18日 · 最后由 ery 回复于 2012年11月19日 · 6969 次阅读

我们有两个 Rails 项目,共用一个数据库 一个是 主站系统 一个是 运维系统 我们希望两个项目共用一个套 Migration 代码。


额外说明,在发布的时候 我们会通过配置 database.yml 让主站系统 和 运维系统 连接到 同一个数据库。


我们正在研究,在开发和测试阶段,怎么做最合适?

我们希望在开发和测试阶段,两个项目都可以独立的创建数据库。

rake db:migrate

我们考虑有以下解决方案:

  • 两个项目放在一个 Git 中,将 Migration 放在一个独立的目录中,两个项目通过 Linux File Link 或 Ruby Require 引用。
  • 两个项目放在一个 Git 中,将 Migration 放在一个项目中,另一个项目通过 Linux File Link 或 Ruby Require 引用。
  • 两个项目放在一个 Git 中,将 Migration 放在一个项目中,另一个项目通过 database.yml 连接到数据库。

  • 两个项目放在两个 Git 中,将 Migration 放在两个项目中,复制 Migration 代码。

  • 两个项目放在两个 Git 中,将 Migration 放在一个项目中,另一个项目通过 Linux File Link 或 Ruby Require 引用。

  • 两个项目放在两个 Git 中,将 Migration 放在一个项目中,另一个项目通过 database.yml 连接到数据库。

  • 三个项目放在三个 Git 中,将 Migration 放到一个 Gem 中。

  • 三个项目放在三个 Git 中,将 Migration 放到一个独立的 Git 中,两个项目通过 Git Submodule 引用。

希望,有相关经验的高人, 能够分享他们的解决方案, 非常感谢!

相关资料

http://stackoverflow.com/questions/2690546/multiple-rails-app-single-mysql-database http://stackoverflow.com/questions/2599920/multiple-applications-with-ruby-on-rails http://stackoverflow.com/questions/10802793/ruby-on-rails-multiple-applications-with-same-model-and-db

还是不太明白这么折腾的目的是什么?为什么要共用一个数据库,建成两个数据怎么了?

#1 楼 @jimrokliu 这是需求决定的。

没有试过,两套 migration 的脚本如果 version id 不一样应该相互不影响吧,虽然只有一张 schema_migrations 的表。

请问,有谁采用过 gem 的方案?

运维和主站是啥意思?都是用 Production 的 Database 的话,只 migrate 一次,然后分别重启两个服务器就好了呀?

#2 楼 @ery 那就解释一下需求吧,不然别人的建议也很难靠谱的说

#6 楼 @fsword 那么,我举一个例子 比如银行系统 主站系统,客户可以登录该网站查询自己的账户余额和明细。 运维系统,银行的工作人员可以登录该网站办理业务。 这两个系统发布的时候,访问的是一个数据库。

但是在开发阶段和测试阶段, 为了简化程序员的操作, 我们希望两个系统可以分别的建立数据库, 而不必依赖另一个系统。

#7 楼 @ery 同步 migration 就可以啊

#5 楼 @ericguo Production 的确是这个样子, 但是 development 和 test 环境下, 你觉得应该怎么做更好哪?

#8 楼 @hooopo 请问怎么同步 migration?

#10 楼 @ery 我前几天看的一个 cms: rake -T

rake refinery_authentication:install:migrations  # Copy migrations from refinery_authentication to application
rake refinery_images:install:migrations          # Copy migrations from refinery_images to application
rake refinery_pages:install:migrations           # Copy migrations from refinery_pages to application
rake refinery_products:install:migrations        # Copy migrations from refinery_products to application
rake refinery_resources:install:migrations       # Copy migrations from refinery_resources to application

refinery_products 等都是这个 cms 的插件

# Specify additional Refinery CMS Extensions here (all optional):
gem 'refinerycms-i18n', '~> 2.0.0'
gem 'refinerycms-blog', '~> 2.0.0'
gem 'refinerycms-inquiries', '~> 2.0.0'
#  gem 'refinerycms-search', '~> 2.0.0'
#  gem 'refinerycms-page-images', '~> 2.0.0'

https://github.com/refinery/refinerycms

然后rake db:migrate:status看哪些还没迁移就再迁移一遍。不知到你的情况和这种一样不。

你这种情况是否可以把迁移文件做成单独的 gem,所有系统引入这个 gem。就解决所有问题了。

我以前一个公司把 asset 单独做成了一个 gem,所有其他系统引入这个 gem。应该和你的情况类似。

当然这两种我都没实践过,可以考虑试一下,建个 demo 项目~

#12 楼 @hooopo 做成 Gem 的确是一个方案, 但是有点麻烦, 我们都很怕麻烦,呵呵, 非常感谢你的推荐。

大哥,哪里麻烦。你现在最不麻烦还能解决问题的方案是什么

之前我们有个项目三个系统,1) 后台管理,2) 主系统,3)API,三套系统独立运行,但数据库是连接同一个,代码是放在不同的 git 中的,但是 db 目录是共享的,也就是@hooopo 说的同步 migration

#14 楼 @hooopo 我们开发过 Gem, 用 Gem 解决这个问题,有点麻烦。 我在上面已经列出了 8 种解决方案, 其中 两个项目放在一个 Git 中,将 Migration 放在一个项目中,另一个项目通过 Linux File Link 或 Ruby Require 引用 我们认为最简单。

仔细看了一下你的描述,你的这两个项目其实是有依赖的。每个单独的项目是运行不起来的,对吧?

#17 楼 @hooopo 两个项目没有依赖关系,完全可以单独运行。

#18 楼 @ery 那做为两个独立的项目,单独开发/测试会有什么问题?或者说你这样搞带来了什么好处?

#15 楼 @Star 谢谢你的回复,能具体说说,你们的 db 目录是如何共享的吗? 是通过 Linux File Link 吗?还是另外一个独立的 Git

其实我最没理解的是这句话:我们希望在开发和测试阶段,两个项目都可以独立的创建数据库。 既然你说两个项目没有依赖,完全可以独立运行。难道还不能独立的创建数据库?

我理解的没有依赖应该是这样的:

project A's database.yml:
development:
  database: development_A
production:
  database: production_C

-

project B's database.yml:

development:
  database: development_B
production:
  database: production_C

然后在开发环境分别做迁移都可以正确运行。

#7 楼 @ery 我理解你所说的场景下有两个 project,一个是前台,一个是管理后台。 解决方案要根据规模来定,小规模的时候可以由一个 project 来负责 migration,另外一个仅仅使用,不负责维护数据结构的升级,具体哪个维护 migration 取决于哪个 project 的变更更频繁。

同步 migration 的做法我没接触过,不过感觉是朝着错误的方向上深入下去了

应该提醒的是,此时要注意分拆 model 的业务逻辑,一个常见的误解是前后台共用一套模型,这个很多时候都是错误的,因为前后台对同一个东西的看法可能是截然不同的,如果共用模型,容易人为造成陷阱。实在重复的代码,可以做成对 model 的增强 gem,然后共用(@hooopo 的方案)

当然,上面说的是小规模,当业务变大的时候就必须朝服务化的方向转移了,所以关键还是要把业务分开

没试过,刚刚想想,如果 model 也要统一的话,搞个软链接来共享 model 文件,不知道是否可行

#23 楼 @huacnlee 你是说 Linux Link File 吗? 我们试过,的确可行, 但是我们这次的项目,不需要统一 Model 层, 就像 #22 楼 @fsword 说的那样, 两个项目对 Model 层的理解完全不同,根本没法共用。

#22 楼 @fsword 非常感谢你的建议。

#21 楼 @hooopo 在两个项目中, 如果,其中一个项目没有 Migration 的代码, 那么,那个项目就无法创建数据库。 理论上,我们两个项目的 Migration 的代码,应该是完全一样的。 问题是,我们如何保证两个项目的 Migration 的代码,完全一样的哪? 而且还不会很复杂,开发成本比较低。

#26 楼 @ery 把一个项目的ActiveRecord::Migrator.migrations_path指向另一个项目的db/migrate目录

看这里的代码,做成 engine 就会自动去加载 engine 里的 migrations。手动设置ActiveRecord::Migrator.migrations_path估计也会起到 engine 的效果。

task :load_config do
    ActiveRecord::Base.configurations = Rails.application.config.database_configuration
    ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a

    if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
      if engine.paths['db/migrate'].existent
        ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a
      end
    end
  end

https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/railties/databases.rake#L26-L33

然后只在一个项目里加 migration 文件。

#27 楼 @hooopo 酷!这真是一个好办法。感觉比 Linux File Link 好。非常感谢!

企业级应用里面对这个的成熟解决方案是针对数据层的 SOA - 除非是玩具项目或者 prototype, 不建议重新发明轮子

两个 model 层对数据库理解完全不同的应用共用一个数据库非常容易造成数据质量问题,除非一个应用是只读,比如是报表这一类。这种情况可以考虑自动镜像 生产环境的数据库到 sandbox 供本地开发使用。同步 migration 的问题是把对数据的依赖转化为对开发流程的依赖,在多团队协作的时候或者开发员经验不足时会太乱。

#20 楼 @ery Sorry, 我刚去看了下以前的项目,07~09 年的老项目了,当时还是用的 svn,不是在本地建的链接,就是在 svn 中同步这个文件的,也就是 svn checkout 这三个项目,得到的 db 里面文件是相同的,不过我们的 model 也是相同的。我们做的外包,是老外那边设置好的,当时我还真不知道怎么设置的,我估计 git 中应该也会有这种机制。不过貌似你已经找到办法了,哈哈。。

#29 楼 @knwang SOA 不适合我们的情况, 如果要采用 SOA 的模式的话话, 我们需要建立第三个项目, 如果今后我们开发 IOS 客户端的话,我们会用 SOA。

因为两个项目的业务逻辑完全不同, 就像你提到的报表, 举个例子, 针对表 1,项目 A 执行读写操作,项目 B 执行只读操作。 针对表 2,项目 B 执行读写操作,项目 A 执行只读操作。 所以说两个项目对 Model 层的理解是完全不同的。

至于镜像生产环境的数据库, 由于我们的项目尚未发布, 所以木有生产环境的数据库。

所以开发和测试阶段, 同步 Migration,是比较适合我们的解决方案。 所以,我们在集中精力思考如何通过 Migration。 Git? File Link? Gem? Copy?

最后,非常感谢你的建议!

#30 楼 @Star 谢谢,SVN 的确可以这样,对应的技术可能是 Git Submodule。

#31 楼 @ery 同步 migration 对开发流程非常制约,举个用 git / gem 的例子:

team 1 creates a migration A, runs it as part of development, but not commit to git / gem yet team 2 creates a migration B, runs it, commit to git / gem team 1 now commits migration A to git / gem after finishing a feature

now team 2 gets a migration A that it hasn't run with stamstamp before migration B that it has run.

如果两个团队都用 git branching 就更复杂了。退一大步说,没有这些复杂的情况,migration 的建立和运行也都是线性的,这种情况需要两边有更新 migration 的时候要立刻向对方大吼要立刻更新,并且 roll back 本地还没有 commit 的 migration。这种互相制约的情况很不利与项目的快速开发。向我上面说的,这是把数据库结构的依赖转化为对开发流程的依赖。

#33 楼 @knwang 我明白你的意思啦,非常感谢你细心的说明。 我们团队的开发流程,和你所描述的情况有些不同, 以下是我们的开发流程:

团队 A 开发项目 A,新建一个 Git Branch A,根据他们的需求随意改动 Migration 团队 B 开发项目 B,新建一个 Git Branch B,根据他们的需求随意改动 Migration 任何一个团队开发结束后, 直接提交代码到对应的 Git Branch 上(A 或 B), 周期一般一周左右。 团队 A 和团队 B 互不影响。

这个时候,团队 C 登场, 团队 C 逐个审查 Branch A 或 B 的代码, 做 Code Review, 审查并重构后, 再逐个提交到 Master Branch 上。

团队 C 最痛苦, 他们也是整个项目的瓶颈。 他们负责整合所有的 Branch。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号