NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

关于运行Active Record数据迁移

| Comments

Active Record数据库迁移是 Active Record提供的一个功能,按照时间顺序管理数据库模式。使用迁移,无需编写 SQL,使用简单的Ruby DSL就能修改数据表,对数据库的操作和所用的数据库种类无关。

你可以把每个迁移看做数据库的一个修订版本。数据库中一开始什么也没有,各个迁移会添加或删除数据表、字段或记录。Active Record知道如何按照时间线更新数据库,不管数据库现在的模式如何,都能更新到最新结构。同时,Active Record还会更新db/schema.rb文件,匹配最新的数据库结构。

db:migrate

Rails提供了很多Rake任务,用来执行指定的迁移。

其中最常使用的是rake db:migrate,执行还没执行的迁移中的change或up方法。如果没有未运行的迁移,直接退出。rake db:migrate按照迁移文件名中时间戳顺序执行迁移。

注意,执行db:migrate时还会执行db:schema:dump,更新db/schema.rb文件,匹配数据库的结构。

db:migrate VERSION

如果指定了版本,Active Record会运行该版本之前的所有迁移。版本就是迁移文件名前的数字部分。例如,要运行 20080906120000 这个迁移,可以执行下面的命令:

1
rake db:migrate VERSION=20080906120000

如果20080906120000比当前的版本高,上面的命令就会执行所有20080906120000之前(包括 20080906120000)的迁移中的change或up方法,但不会运行20080906120000之后的迁移。如果回滚迁移,则会执行 20080906120000之前(不包括20080906120000)的迁移中的down方法。

db:rollback

还有一个常用的操作时回滚到之前的迁移。例如,迁移代码写错了,想纠正。我们无须查找迁移的版本号,直接执行下面的命令即可:

1
rake db:rollback

这个命令会回滚上一次迁移,撤销 change 方法中的操作,或者执行 down 方法。如果想撤销多个迁移,可以使用 STEP 参数:

1
rake db:rollback STEP=3

这个命令会撤销前三次迁移。

db:redo

db:migrate:redo 命令可以回滚上一次迁移,然后再次执行迁移。和 db:rollback 一样,如果想重做多次迁移,可以使用 STEP 参数。例如:

1
rake db:migrate:redo STEP=3

这些 Rake 任务的作用和 db:migrate 一样,只是用起来更方便,因为无需查找特定的迁移版本号。

db:migrate:up和db:migrate:down

如果想执行指定迁移,或者撤销指定迁移,可以使用db:migrate:up和db:migrate:down任务,指定相应的版本号,就会根据需求调用change、up或down方法。例如:

1
rake db:migrate:up VERSION=20080906120000

这个命令会执行20080906120000迁移中的change方法或up方法。db:migrate:up 首先会检测指定的迁移是否已经运行,如果Active Record任务已经执行,就不会做任何操作。

修改现有的迁移

有时编写的迁移中可能有错误,如果已经运行了迁移,不能直接编辑迁移文件再运行迁移。Rails 认为这个迁移已经运行,所以执行 rake db:migrate 任务时什么也不会做。这种情况必须先回滚迁移(例如,执行 rake db:rollback 任务),编辑迁移文件后再执行 rake db:migrate 任务执行改正后的版本。

一般来说,直接修改现有的迁移不是个好主意。这么做会为你以及你的同事带来额外的工作量,如果这个迁移已经在生产服务器上运行过,还可能带来不必要的麻烦。你应该编写一个新的迁移,做所需的改动。编辑新生成还未纳入版本控制的迁移(或者更宽泛地说,还没有出现在开发设备之外),相对来说是安全的。

在不同的环境中运行迁移

默认情况下,rake db:migrate 任务在 development 环境中执行。要在其他环境中运行迁移,执行命令时可以使用环境变量 RAILS_ENV 指定环境。例如,要在 test 环境中运行迁移,可以执行下面的命令:

$ rake db:migrate RAILS_ENV=test

参考资料:
1.http://guides.ruby-china.org/active_record_migrations.html

Spring AOP 深入了解(一)还给业务逻辑代码一个干净的世界

| Comments

本篇博客系列的目的:

之前一直想要实现一个日志类库:https://github.com/benweizhu/LoggerUtil

用来记录某个方法在调用前,调用后,抛出异常后的一些信息,比如方法名,参数,返回值。还希望可以指定记录的格式以及日志的级别(INFO,DEBUG等)。最关键的是,这个日志类库,必须有通用性和不可以有侵入性,这就导致它必定通过AOP来实现。

于是,为了做到这一点,现在我们就来深入的学习一次AOP:

为什么要AOP

编程语言最终极的目标就是能以更自然、更灵活的语言的方式模拟世界,从原始机器语言到过程语言再到面向对象的语言(OOP)。AOP提供了与OOP不同的另外一种方式来思考软件架构。OOP的模块单元是“类”,而AOP的模块单元“面”(Aspect)。

那么问题来了,什么是“面”?以及什么“面向切面编程”?

AOP被翻译成“面向方面编程”,“面向切面编程”,所以这里我更倾向于将“面”理解为“切面”(Aspect)。

从字面上理解,“切面”来自几何学,在立体几何中,切面是指用一个平面去截一个几何体(包括圆柱,圆锥,球,棱柱,棱锥、长方体,正方体等等),得到的平面图形。

那什么是“面向切面编程”?就是在该切面上加入一些逻辑操作(可以简单理解为“面向切面的操作”)。举个最常见的例子:

扑克牌的切牌,你可以将“广告牌”切入在任何你想要切入(或插入)的位置(你可以对扑克牌的任何一个切面做切牌操作)。插入的位置就是切面,插入的广告牌就是逻辑操作。

又或者是“斗地主”中,第一把不知道谁是地主,于是将一张牌反插入到牌的中间。本来应该按照顺序发牌,并不能知道谁是地主,但是因为你在某个位置插入了一个特殊操作(将一张牌反插入),因为多了一个逻辑,所以可以知道谁是地主。(或者将广告牌插入中间,也可以知道谁是地主)

这是“面向切面的编程”的最基础理解。

也许你还是不能理解面向切面编程,最重要是你并不知道为什么需要它,即何时需要它?

在OO的世界里,我们操作的是对象,创建一个对象并使用对象的属性和方法,而对象有抽象和继承的特性,因此,我们会利用抽象和继承的特性来消除重复的代码。

我们知道,编程语言是从原始机器语言到过程语言再到面向对象的语言,但是即便是OO的世界,我们也逃离不了面向过程的编程方式,代码的每一步操作一定是有顺序的,因为机器解释代码也是按顺序执行的。

代码按照顺序执行无可厚非,遇到重复的代码,我们利用抽象的方式,将重复的部分抽离成一个独立模块(方法或者类),由所有需要的地方重用即可。

但有一种顺序代码,它重复使用在不同的固定位置,它与业务代码无关,通过OO的常用办法并不能消除这种模式的重复,比如:事务管理,性能监控(和控制)。

1
2
3
4
5
public void addUser(){
  transactionManager.beginTransaction();
  ..
  transactionManager.commit();
}

我们知道这些重复性的代码逻辑,是可以非常轻松的独立出来,比如,beginTransaction和commit方法,但,我们无法通过抽象的方式来消除这种重复的调用,因为它和业务代码具有关联性,它依附在业务代码的顺序流程中。

有人说,可以采用模板方法(设计模式中的一种模式),这样可以消除重复,但也导致所有使用模板方法的类,都要重写模板中的其中一步(某个方法)来实现业务逻辑,重写方法是不能改变方法的名字。这样就给代码的自描述性带来了困难,得不偿失。

好在AOP希望做得到的就是,将这些分散在各个不同业务逻辑代码中的相同代码,通过切入的方式,将这块具有顺序性关联的逻辑抽离到独立模块,而在逻辑代码中将看不到之前重复的逻辑。

从而,还给业务逻辑代码一个干净的世界。这就是AOP给我们带来的好处。

参考资料:
1.Spring 3.0就是这么简单
2.http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/aop.html