我发现写Rails,尤其是测试部分,需要reload的次数相当频繁。比方说

user = users(:xxxxx)
xhr :put, 'change_xxxxx', :id => user.id
user.reload # necessary!
assert user.xxx, xxx
assert user.yyy, yyy

由于这里创建的user对象和被测试的action里的user对象(在内存概念上)不是同一个对象,因此,被测试的action修改了user对象在数据库里的数据,会导致外围的user信息过时,因此必须reload,否则接下来的断言语句都无法通过。

这种情况同样也有可能存在与关联对象上,比如

assert child1.father, child2.father
child1.father.name = 'new name'
child1.save
child2.reload # necessary!
assert child2.father.name, 'new name'

总是写很多reload语句显然很不舒服,为此我今天在回家的地铁上想了一种解决方案,就是在后台全局的部分,以ActiveRecord类名和实例为key简单的缓存一部分数据,这部分数据与数据库里的数据在本次request返回内一致,request结束后自动清除以免内存泄露和影响下一个request。而前面的ActiveRecord对象,本身仅存储那些还未被保存的数据。

方案大致是这样的(以Rails 2.3为例):

require 'active_record'

module ActiveRecord
  class Base
    def request_cache
      self.class.request_cache[self]
    end

    def request_cache=(v)
      self.class.request_cache[self] = v
    end
  end

  class << Base
    def request_cache
      @request_cache ||= Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = {}}}
      @request_cache[name]
    end
  end
end

ActionController::Dispatcher.middleware.use(Class.new do
  def initializer(app)
    @app = app
  end

  def call(env)
    @app.call(env)
  ensure
    ActiveRecord::Base.request_cache.clear
  end
end)

这里我把缓存就设计在ActiveRecord的class variable内(三级Hash,分别是类-实例对象-属性名),然后用Middleware的方式去清理缓存,之所以选择用Middleware的方式是因为ActiveRecord原本和HTTP Request是不能发生关联的,否则Console和Unit test里就无法执行了,设计成Middleware则能很好的解决这一问题。

由于选择的三级Hash的设计中没有直接和数据库关联的信息,因此其实也可以用于非ActiveRecord类(唯一要做的可能仅仅是自己实现一种标示方法),毕竟当前可以用于存储的服务早已不止数据库一种了。

至于对于ActiveRecord的修改我现在对ActiveRecord的实现还不够熟悉,无法完成,以后学习这一部分了再说吧。但是大致的思路是这样的:

  • 当从数据库读入数据的时候(包括reload),将缓存里的数据翻新
  • 当保存数据进数据库的时候,将数据同样保存进缓存
  • 当从一个ActiveRecord对象读取属性的时候,现在被当前对象修改过的属性中搜索,如果搜索不到再从缓存里搜索,如果还是搜索不到就采用默认方法

大致就是这些了,其实想法还是很简单的,希望早日自己能把它变成现实。

由于电脑重装的缘故,我虚拟机里的Oracle数据库也重新安装了,因为OCP已经考完,我配置的数据库显然不能再局限于OCP考试之用,再说我本来也喜欢开发,而不是做DBA,我计划着让他和PHP连接起来,模仿生产环境,所以在编码上我使用了UTF-8字符集,而不是传统的美式字符。安装自然是一切顺利,不过在打开EM时却发生了java.lang.Exception: Exception in sending Request::null的错误,这个错误以前从未发生过,重启也无效。我估摸着大概是字符集的问题,于是Google下,找到了解决方法:

gedit $ORACLE_HOME/sysman/config/emd.properties

在最后添加agentTZRegion=Asia/Shanghai 重启EMCTL就可以了。

我在上海,所以使用上海的时区。

可以使用 gedit $ORACLE_HOME/sysman/admin/supportedtzs.lst 来找到支持的时区。

参考文献:

hi.baidu.com/zxq211103/blog/item/f00a7a63ad47fc620c33fa0d.html
forums.oracle.com/forums/thread.jspa?threadID=320574&tstart=0&messageID=1374397

Oracle笔记—警示线

2010年9月11日 23:40

一些系统级的Warning警示线和Critical警示线谁大谁小没有严格规定。而像表空间这样的Warning警示线必须严格小于Critical警示线。其实我觉得严格小于是对的,不作规定反倒是很奇怪的。

Oracle笔记—Large Pool的作用

2010年9月11日 23:29

下面对象使用Large Pool:

MTS

—在SGA的Large Pool中分配UGA,语句的并行查询。

—允许进程间消息缓冲区的分配,用来协调并行查询服务器,备份。

—用于RMAN磁盘I/O缓存。

Oracle笔记—PL/SQL关键字问题

2010年9月11日 23:22

大概最容易用到的是SUM吧,Oracle内置函数名字,也是非常常用的变量名字,所以要注意,不要触及关键字。

Oracle笔记—Trace与Track

2010年9月11日 23:16

Oracle既有一个Track文件,也有一个Trace文件,Track和Trace解释很相近,以至于我长期搞不清楚他们的关系。

 

跟踪文件(trace file)能提供调试信息,服务器遇到问题时,它会生成一个包含大量诊断信息的跟踪文件。如果开发人员设置了sql_trace=true,服务器就会生成一个包含性能相关信息的跟踪文件。我们之所以可以使用这些跟踪文件,是因为oracle是一个允许充分测量的软件。编写数据库内核的程序员在内核中放入了调试代码,而且调试代码相当多,这些调试代码是被程序员有意留在内核中的。

 

修改跟踪文件(change tracking file)是一个可选的文件,这是oracle 10g企业版中新增的,这个文件惟一的目的是跟踪自上一个增量备份以来哪些块已经修改。采用这种方式,恢复管理器(recovery manager,rman)工具就能只备份确实有变化的数据库块,而不必读取整个数据库。
在oracle 10G之前的版本,要完成增量备份,必须读取整个数据库文件,查找自上一次增量备份以来修改的块,如果有一个1T的数据库,只增加了500M的新数据,增量备份就必须读取1T的数据,在其中找出要备份的500M新信息,尽管增量备份存储的数据确实少得多,但它还是要读取整个数据库。
在10G企业版中,oracle运行时,如果块被修改,oracle可能会维护一个文件,告诉RMAN哪些块已经修改。创建这个修改跟踪文件的过程相当简单,只需要通过ALTER DATABASE命令就可以完成:

Oracle笔记—CORE_DUMP_DEST

2010年9月11日 23:07

如果出现严重的oracle内部错误,或是oracle support要求你生成一个跟踪文件来得到额外的调试信息,CORE_DUMP_DEST参数则定义了此时这个“内核”文件应该放在哪里。

Oracle笔记—关于ASM_POWER_LIMIT

2010年9月11日 06:54

一直以为ASM_POWER_LIMIT是越小速度越快,但其实是越大速度越快拉。。

 

ASM_POWER_LIMIT specifies the maximum power on an Automatic Storage Management instance for disk rebalancing. The higher the limit, the faster rebalancing will complete. Lower values will take longer, but consume fewer processing and I/O resources.
 
If the POWER clause of a rebalance operation is not specified, then the default power will be the value of ASM_POWER_LIMIT.
 
引用自:http://united-states.frommeyer.nl/documentation/oracle/database/10.1/server.101/b10755/initparams012.htm

在10g中创建字典管理表空间都会出现这样一个错误:Failed to commit: ORA-12913: Cannot create dictionary managed tablespace

查询Oracle官方文档:

 

ORA-12913: Cannot create dictionary managed tablespace

Cause: Attemp to create dictionary managed tablespace in database which has system tablespace as locally managed

Action: Create a locally managed tablespace.

 

这是因为:

 

在Oracle920中,默认系统表空间是local管理,因此不能在数据库中建立数据字典管理的表空间。


如果想要建立数据字典管理的表空间,必须在建立数据库时,将系统表空间改为数据字典管理才可以。

 

一个是环境变量,一个是数据库参数。
 
nls_lang是在客户端设置设置客户端字符集,也就是在环境变量(Linux:~/.bash_profile)中。
 
nls_language在服务端设置,SERVER端的lang,属于parameter,可以由alter system set nls_language='...' scope=spfile 来修改。
 
nls_characterset也是设置服务器的字符集。