Rails datetime类型在mysql数据库中的精度问题

在我的博客网站开发过程中,我在开发环境使用sqlite3,而在生产环境则使用性能更好的mysql。一直以来我也觉得没什么,因为rails会屏蔽所有的数据库差异。但这样也带来一些问题,其中一个就是schema.rb的版本控制问题。Rails建议对此文件进行版本控制,这样可以更清楚的看到数据库版本的变动。但由于开发和生产环境使用的数据库不一致,导致每次rake db:migrate后schema.rb都会变化,开发环境和生产环境的这个文件版本不一致(由于数据库的不同),将测试环境的schema.rb传到版本控制显然不好,但是不传的话总是提示有文件未提交感觉很不好。

经过权衡决定在测试环境也使用mysql,并且将测试数据也导入到新的mysql数据库。数据库不一致的另一个问题是我在迁移时发现的,不同的数据库还是有差异的,而且还影响到测试案例的成功与否,其中一个问题就是这次要重点介绍的datetime类型的精度问题。

datetime类型是rails在generate model时自动生成的,如果执行

$ bin/rails generate model Product name:string description:text 

会生成一个迁移文件如下:

#file name: db/migrate/20160501090706_create_products.rb
class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.string :name
      t.text :description
 
      t.timestamps null: false
    end
  end
end 

其中 t.timestamps null: false会生成2个字段created_at,updated_at,其schema.rb中的

#file name : schema.rb
#...
    t.datetime "created_at"
    t.datetime "updated_at"
#...

这种datetime类型的字段是作为时间戳使用的,在sqlite3中为6位精度,如2016-05-01 11:28:38.860909,这没有问题。但是换为使用mysql就有问题了,datetime 类型在mysql中默认精度只到秒,这显然不能满足要求,秒级的时间戳是没有意义的。在网上找了很多资料,有很多比较陈旧,下面把我测试通过的解决方法记录一下,方便大家参考1 2

在Rails 4.2的Release Notes有下面一句话:

Added support for fractional seconds for MySQL 5.6 and above

可以看出Rails 4.2已经支持日期精度功能,关于mysql的fractional seconds功能可以参考 mysql reference.

我们在Rails 4.2+应用中应该如何使用此功能呢?可以通过添加migrate文件来解决,具体如下:

 bin/rails g migration ChangeDatetimeLimitForMysql 

在生成的文件中修改如下:(下面只以修改一个表为例,多个表修改方法类似)

# file name: db/migrate/20160501090706_change_datetime_limit_for_mysql.rb
# mysql 5.6.4以上的版本支持分数精度(fractional seconds),默认mysql精度只到秒
# limit 置为 6 精确到微妙;如将limit 修改为 3 则精确到毫秒

class ChangeDatetimeLimitForMysql < ActiveRecord::Migration
  def up
    change_column :comments, :created_at, :datetime, limit: 6
    change_column :comments, :updated_at, :datetime, limit: 6

     #...
  end
  
  def down
    change_column :comments, :created_at, :datetime
    change_column :comments, :updated_at, :datetime

    #...
  end
end 

然后执行rake db:migrate即可,这样之后新增修改的记录的时间戳都会精确到微秒。注意测试环境也需要执行rake db:test:prepare使其生效。

[注]:此方案适用于Rails 4.2+,mysql 5.6.4+.

参考资料:

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》

留言:

随便说说

Hi, i think that i saw you visited my website so i
got here to go back the favor?.I am trying to find issues to
enhance my web site!I suppose its ok to make use of some of your ideas!!

http://www.itechlib.com is amazing website, bookmarked!

Hello. I have checked your itechlib.com and i see you've got some
duplicate content so probably it is the reason that you don't rank high in google.
But you can fix this issue fast. There is a tool that generates articles like human, just
search in google: miftolo's tools

(lesstile enabled - surround code blocks with ---)