好文章,看的酣畅淋漓。对于"touch"有一些小 comment。
@rainchen “这个更多是一个 view 层面 render 时要顾虑的东西” (要 decouple View 和 Model),引申一下这个观点,我们使用 russian-roll caching 的时候,我觉得需要了解 touch 机制的局限,并且尽量把 view 和 model 解耦。
数据库写操作的 Scalability 被'touch'的表将有可能变成 bottleneck,比如 project 这个 root node,它的读写操作会是子孙 node 的总和(由于 leaf node 会 populate 整个 touch chain,所以不单单是 child node 了)所以,有越多的 leaf node 加进来,ancestor node 就一直被 touch,写操作比较难 scalable 了。当然,读操作的效率很高,因为如果 root node 没变,就不用 touch child node 了。
Coupling 数据库 table 之间的 reference 关系和 view 的层次被 couple 到一起了。一旦 view 之间的相互关系变了,touch 也要相应的改变。而且,数据库里要存 foreign key 来形成这个 touch chain,这些 key 也许从 data modeling 的角度都是冗余信息,只是为了 view 的嵌套方便。
所以 touch 适用的范围是,外层大套娃的 table 轻量,view 的结构基本不变,和 model 有一致的层次关系(view 的对应的套娃和 model 的套娃的套法是相近的)。
也许楼主的 use case 就是如此,所以做了那样的 design。
@hooopo 顶。 单单从 Database 的角度来说,就要避免用 default_scope。因为 order/where 和 default scope 混到一起后,产生的 query 有可能非常低效,一个 naive 的例子,你在 hits 上有 index,created_at 上面没有,那你的取 sort by hits 的 query 本可以只做 B-tree scan,再去取相应的 table rows,由于 default_scope,现在就必须做一个 full table scan(因为 created_at 需要到 table 里面取)。
就算你在 created_at 上面加了一个 index,由于有两个 column 需要 sort,也要消耗额外的内存,做额外的 I/O 操作。总之,default_scope 几乎就是用 DB 的消耗来换 syntax sugar。don't be lazy,把你需要的操作明确地写出来,否则就可能发生你意想不到的事情。
你说的情况可能只适用于本地 dev 环境或者 prod 环境的测试,因为有对应的数据库产生来临时的 schema 文件,从而生成 in-memory DB。但是如果使用 remote build 系统,那么远程的 host 是不会有数据库连接的,那么在 build 的时候就找不到 schema 文件,无法进行测试。
其次,测试用的 SqlLite 的数据库有一些自己特别的限制,比如 index name 必须 unique。如果由本地数据库(如 MySql)产生的 schema 存在重复的 index name,那么 SqlLite 无法直接读入 schema 进行测试,每个 developer 都需要手动来改动 schema 文件,很浪费时间(发生在身边很多次)。
再着就是会发生楼主所说的情况,可能 migration 相互有冲突,无法依次执行 migration 来建立 DB,这时候一个比较简单的办法就是利用 schema 直接产生没有 data 的本地数据库。所以,schema 文件一般是要 check in 的。
@jossjoss54 你是在运行 migrate 时总遇到 table already exist 么?要么你们的 migration 文件不 consistent,要么你的本地数据库和远程数据库曾经进行过 sync 一部分 table,但是对应的 schema_migrations 表没有 sync。 有没有办法判断所有的栏位是否相同,若相同则不更新,不同则更新?是什么意思?你想要机器自动判断 table 是否一致自动运行 migration 么?
@libuchao 解释的蛮清楚的了。
比较 naive 的 server 端代码本身可能是
SELECT * FROM projects WHERE name = '#{name}'
所以如果你输入的是 "' OR 1 --
" (注意 single quote 不是结束查询,而是和 server 端的#{name}前面的 single quote 配对,如果没有 single quote,那么所有的注入代码还是被当做 string 来解析,就无法用--
起到注释的作用了)。
替换后:
SELECT * FROM projects WHERE name = ' ' OR 1 -- whatever_sql_code
@young4u_amy 如果你用错误密码连接 DB,那么 new 的返回值是什么?MySql2 的连接错误是抛出 exception 还是,默默地把 client 设置成 nil?如果是后者的话,那确实捕捉不到 exception,因为没抛。
@badboy schema 不加到代码库里面,那么 test 文件的 in-memory DB 如何产生相应的 table structure?
“access_log 是个很有用的东西,但是考虑到 logrotate 和 fd 的问题,还是不太适合在用户级的应用上使用。” 请教,能否具体阐释一下 logrotate 和 fd(这是什么的缩写?)的问题?
可以使用 IF 控制语句。具体语法还要看你使用的是那种数据库。