资料库迁移- Migrations

资料库迁移- Migrations

Migrations(资料库迁移)可以让你用Ruby 程式来修改资料库结构。 相较于直接进资料库系统使用SQL 修改结构(例如使用phpMyAdmin 工具来修改),使用Migrations 可以让我们有记录地进行资料库修改,每次变更就是一笔Migration 记录。 在没有Migration 之前,如果你手动修改了资料库,那么你就必须通知其他开发者也进行一样的修改步骤。另外,在正式布署的伺服器上,你也必须追踪并执行同样的变更才行。 而这些步骤如果没有记录下来,就很容易出错。

Migrations 会自动追踪哪些变更已经执行过了、那些还没有,你只要新增Migration 档案,然后执行rake db:migrate 就搞定了。 它会自己搞清楚该跑哪些migrations,如此所有的开发者和正式布署的伺服器上,就可以轻易的同步最新的资料库结构。 另外一个优点是: Migration 是独立于资料库系统的,所以你不需要烦恼各种资料库系统的语法差异,像是不同型态之类的。 当然,如果要针对某个特定资料库系统撰写专属功能的话,还是可以透过直接写SQL 的方式。

新增一个Migration 档案

执行以下指令,就会在db/migrate/ 目录下产生如20110203070100_migration_name.rb 的档案

rails g migration migration_name 

注意到在migration_name.rb 前面有着如YYYYMMDDHHMMSS 的时序前置,用来表明执行的顺序。在早先的Rails 版本中,是使用编号1,2,3 来指名执行的顺序,但是如果有不同分支多人开发就可能会有重复的编号,因此在Rails 2.1 之后的版本改采用时间戳章,让Rails 能够应付多人开发的状况。

migration_name常见的命名方式有Add欄位名To表格名或是Remove欄位名To表格名 ,不过这没有一定,能描述目的即可。

让我们打开这个档案看看:

 class MigrationName < ActiveRecord::Migration def up end def down end end 

在这个类别中,包含了两个类别方法分别是up 和down。 其中up 会在执行这个migration 时执行,反之down 会在滚回(Roll back)这个Migration 时执行。 例如,我们在up 时新增一个资料库表格(table),那么就可以在down 的时候把这个table删除。

Migration 可用的方法

在up或down方法里,我们有以下方法可以使用​​:

对资料表做修改:

  • create_table(name, options) 新增资料表
  • drop_table(name) 移除资料表
  • rename_table(old_name, new_name) 修改资料表名称
  • change_table 修改资料表栏位

个别修改资料表栏位:

  • add_column(table, column, type, options) 新增一个栏位
  • rename_column(table, old_column_name, new_column_name) 修改栏位名称
  • change_column(table, column, type, options) 修改栏位的型态(type)
  • remove_column(table , column) 移除栏位

新增、移除索引:

  • add_index(table, columns, options) 新增索引
  • remove_index(table, index) 移除索引

记得将所有外部键foreign key 加上索引

新增和移除Table

执行rails g model 时,Rails就会顺便新增对应的Migration 档案。 以上一章产生的categories migration为例:

 class CreateCategories < ActiveRecord::Migration def change create_table :categories do |t| t.string :name t.integer :position t.timestamps end add_column :events, :category_id, :integer add_index :events, :category_id end end 

其中的timestamps 会建立叫做created_at 和updated_at 的时间栏位,这是Rails的常用惯例。 它会自动设成资料新增的时间以及会后更新时间。

疑,这里怎么不是用updown方法? Rails 3.1版新增了change方法可以很聪明的自动处理大部分down的情况,上述情况的down就是移除catrgories资料表和移除eventscategory_id栏位,因此就不需要分别写updown了。 如果Rails无法判断,会在跑rake db:migrate时提醒你不能用change ,需要分开写updown 。

修改Table

我们来试着新增一个栏位吧:

 rails g migration add_description_to_categories 

打开db/migrate/20110411163049_add_description_to_categories.rb

 class AddDescriptionToCategories < ActiveRecord::Migration def change add_column :categories, :description, :text end end 

完成后,执行bundle exec rake db:migrate便会实际在资料库新增这个栏位。

资料库的栏位定义

为了能够让不同资料库通用,以下是Migration中的资料型态与实际资料库使用的型态对照:

Rails中的型态 说明 MySQL Postgres SQLite3
:string 有限长度字串 varchar(255) character varying(255) varchar(255)
:text 不限长度文字 text text text
:integer 整数 int(4) integer integer
:float 浮点数 float float float
:decimal 十进位数 decimal decimal decimal
:datetime 日期时间 datetime timestamp datetime
:timestamp 时间戳章 datetime timestamp datetime
:time 时间 time time datetime
:date 日期 date date date
:binary 二进位 blob bytea blob
:boolean 布林值 tinyint boolean boolean
:references 用来参照到其他Table的外部键 int(4) integer integer

另外,栏位也还有一些参数可以设定:

  • :null是否允许NULL ,预设是允许
  • :default预设值
  • :limit用于string 、 text 、 integer 、 binary指定最大值

例如:

 create_table :events do |t| t.string :name, :null => false, :limit => 60, :default => "N/A" t.references :category # 等同於t.integer :category_id end 

参考资料: ActiveRecord::ConnectionAdapters::TableDefinition

栏位名称惯例

我们已经介绍过了timestamps 方法会自动新增两个时间栏位,Rails 还保留了几个名称作为惯例之用:

栏位名称 用途
id 预设的主键栏位名称
{tablename}_id 预设的外部键栏位名称
created_at 如果有这个栏位,Rails便会在新增时设定时间
updated_at 如果有这个栏位,Rails便会在修改时设定时间
created_on 如果有这个栏位,Rails便会在新增时设定时间
updated_on 如果有这个栏位,Rails便会在修改时设定时间
{tablename}_count 如果有使用Counter Cache 功能,这是预设的栏位名称
type 如果有这个栏位,Rails便会启动STI功能(详见ActiveRecord章节)
lock_version 如果有这个栏位,Rails便会启动Optimistic Locking功能(详见ActiveRecord章节)
Migration 搭配的Rake 任务
  • rake db:create 依照目前的RAILS_ENV 环境建立资料库
  • rake db:create:all 建立所有环境的资料库
  • rake db:drop 依照目前的RAILS_ENV 环境删除资料库
  • rake db:drop:all 删除所有环境的资料库
  • rake db:migrate 执行Migration动作
  • rake db:rollback STEP=n 回复上N个Migration 动作
  • rake db:migrate:up VERSION=20080906120000 执行特定版本的Migration
  • rake db:migrate:down VERSION=20080906120000 回复特定版本的Migration
  • rake db:version 目前资料库的Migration版本
  • rake db:seed 执行db/seeds.rb 载入种子资料

如果需要指定Rails环境,例如production,可以输入RAILS_ENV=production rake db:migrate

种子资料Seed

种子资料Seed的意思是,有一些资料是应用程式跑起来必要基本资料,而这些资料的产生我们会放在db/seeds.rb这个档案。 例如,让我们打开来,加入一些基本的Category资料:

 # This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # # Examples: # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) Category.create!( :name => "Science" ) Category.create!( :name => "Art" ) Category.create!( :name => "Education" ) 

输入rake db:seed就会执行这个档案了。 通常执行的时机是第一次建立好资料库和跑完Migration之后。

资料Migration

Migrations 不只可以用来变更资料表定义,它也很常用来迁移资料。 新增或修改栏位时,还蛮常也需要根据现有的资料,来设定新栏位的值。 这时候我们就会在Migration 利用ActiveRecord 来操作资料。

不过,如果你在Migration中修改了资料表栏位,随即又使用这个Model来做资料更新,那么因为Rails会快取资料表的栏位定义,所以会无法读到刚刚修改的资料表。 这时候有几个办法可以处理:

第一是呼叫reset_column_information 重新读取资料表定义。

第二是在Migration 中用ActiveReocrd::Base 定义一个新的空白Model 来暂时使用。

第三是用execute 功能来执行任意的SQL。

Production上跑Migration注意事项

当有上万笔资料的时候,如果有修改资料库表格ALTER TABLE的话,他会Lock table无法写入,可能会跑好几个小时很难事前预估。 建议用staging server用接近production的资料来先测试会跑多久。

bulk参数

:bulk => true可以让变更资料库栏位的Migration更有效率的执行,如果没有加这个参数,或是直接使用add_column 、 rename_column 、 remove_column等方法,那么Rails会拆开SQL来执行,例如:

 change_table(:users) do |t| t.string :company_name t.change :birthdate, :datetime end 

会产生:

 ALTER TABLE `users` ADD `im_handle` varchar(255) ALTER TABLE `users` ADD `company_id` int(11) ALTER TABLE `users` CHANGE `updated_at` `updated_at` datetime DEFAULT NULL 

加上:bulk => true之后:

 change_table(:users, :bulk => true) do |t| t.string :company_name t.change :birthdate, :datetime end 

会合并产生一行SQL :

 ALTER TABLE `users` ADD COLUMN `im_handle` varchar(255), ADD COLUMN `company_id` int(11), CHANGE `updated_at` `updated_at` datetime DEFAULT NULL 

这对已有不少资料量的资料库来说,会有不少执行速度上的差异,可以减少资料库因为修改被Lock锁定的时间。

更多线上资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值