1
Livid MOD 关于 .key().id() 的问题,可能是因为我还没有完全理解及实验充分。但是我看到的问题是:
1. 这个东西貌似不是加一递增的? 2. 可以自己指定么? 保留传统的自增 id 是 V2EX 在规划时我觉得必须要有的一个功能,于是就用了 counter + num 的方式实现。 |
2
Livid MOD 把和 model 有关的东西写在 model 里我非常同意,这也是以后的代码方向。
|
3
Livid MOD HomeHandler 在 /my/ 及相关设置做好之后会重构。
代码这样的东西,说到底是为运营服务的。 有的时候,为了上线的时间和运营的需要,我可能更多关心的是如何让一个能跑的东西尽快 up and running,代码的美观性不是我的主要考虑因素。 而且代码风格这样的东西,当你同时在用多种语言编程的时候,比如我现在每天都会用到 C / Objective-C / PHP / Python,有的时候确实稍不注意就会出现很奇怪的合体产物了。 |
4
Los 2010-11-17 17:26:26 +08:00
嗯,建议逻辑上尽量减少if之类语句的嵌套,这样逻辑会清晰不少
|
5
c 2010-11-17 18:21:07 +08:00
有些东西在很久前都建议过,没有菜我,也许我太菜了吧。
不过也无所谓,存在即为合理 |
6
c 2010-11-17 18:22:34 +08:00
key().id()不能自定义,
可以用key().name()啊,这个只是稍微比key().id()慢那么一点点。 |
7
keakon OP @Livid
key id可以自定义,例如构造一个Topic实体,id为123: Topic(key=db.Key.from_path('Topic', 123)) 不过,非要以1递增不知道有什么用意,似乎排序时不需要按id来排列,都是以时间来排序的 不使用事务或加双重锁的话,2个人同时post 2个topic时,很可能会覆盖掉其中一个 |
10
Livid MOD @c 所以我对你开始做自己的论坛程序这件事情,感到非常赞赏。做比说更有价值。
欢迎大家关注 @c 的作品: http://xfox.appspot.com/ 我暂时还没有时间去看 @c 的代码,不过我相信他肯定比我写得好。 |
11
c 2010-11-17 19:17:23 +08:00
@Livid xFox不会再继续开发了,因为有些问题解决不了 :) 所以现在把2008年的一个相册拿出来重写了一下。
我不认为我的代码比你的好,我只是认为你的代码本来可以写的更优雅一点,因为将来会有很多人看你的代码。 |
12
keakon OP @c 不一样,你用get_by_id()和get_by_key_name()取一下就会发现,1和'1'都可以存在,并且表示的是2个不同的实体。
此外用key_name构造的key会比id要大,且随key_name长度而增长,而id是定长的int64。 实际上我习惯用key_name来减少一个唯一字段,找不到这种字段时,我才会用id 例如用户类,id对我来说没有任何作用,那么我就会拿用户名或email这种唯一字段来做key_name;而文章类虽说可以强制要求URL唯一,但URL是有可能去改动的,所以仍然只能选择id |
13
darasion 2010-11-17 19:19:49 +08:00
话说,事务处理这个地方我一直就没弄明白。
到底谁和谁一起可以做一个“Entity Group”? 这个我总是搞不懂。。。 |
14
Livid MOD @keakon 个人页面上的“V2EX 的第 # 号注册会员”这个功能,在最早那个版本的 V2EX 上就有,所以这次在 GAE 上重建时,我当然希望尽可能复现以前所有的要点。
|
16
keakon OP 只能说效率几乎是一样的,但是key_name生成的key比较大,因此实体及其索引(每个索引都包含key)也会多占用一些空间
此外key只能get,在query时基本上没什么用处,所以如果想取key name是'1'开头的实体就很难了,至少文档里没有介绍__key__比较是否能用于这种情况 |
17
c 2010-11-17 19:33:48 +08:00
|
18
keakon OP @c
这样就不得不多占用存储空间了。而且正如前面所说,假如你的实体生成以后,突然发现slug里有错别字,不得不更改,你就只能删掉重新创建一个实体了。而如果这个实体还是根实体的话,整个实体组可能都得重新创建。 @darasion 在构造实体(准确来说是它的key)时可以指定一个实体为它的父实体。而且这个实体也可以作为其他实体的父实体。 由于一个实体最多只能有1个父实体(但是可以有多个子实体),所以一直向上总能找到一个没有父实体的实体,它就是这个实体组的根实体。 在单个事务中,你只能更改1个实体组里面的实体。 举例来说,如果把Reply的父实体定为Topic的话,用户在post一个reply时,就能在事务中完成创建Reply实体并将它的父实体Topic的reply字段加1。 而如果它们不在一个实体组,你就只能先put一个Reply实体,然后再找到对应的Topic实体,再给它的reply+1。而如果你Reply实体put成功,Topic实体put失败,那么就存在不一致了。 Google给出的方式是分离事务,也就是用一个task来执行Topic的保存,因为task在失败时会自动重试,直到成功。 更常见的例子,如果不使用事务的可能造成这种情况: 1.一个用户a的访问使得你得给Topic的hit加1,于是你取出了这个topic。 2.同时,另一个用户b也要编辑这个Topic的content字段,于是也取出了这个topic 3.b编辑完了,保存成功。 4.a的hit += 1执行完了,也进行保存,但是这个topic的content字段是a取出来时的内容,于是这次保存就让b的编辑无效了。 而单个实体本身就是一个实体组,因此自然可以使用事务,它就可以保证2个人取出数据到保存成功这个过程是串行的,相互之间不会覆盖。 |
19
darasion 2010-11-17 20:14:00 +08:00
@keakon 谢谢解答。
还有几个问题, 1、如果我想在一个方法里边更新很多类( Kind ),而不是one Topic-many Reply这种简单的形式,那么这样的实体组怎样规划?有没有一些模式可以套用? 2、在一个已经存在的,没有规划 事务/实体组 的项目中,引入 事务/实体组 后,应该如何迁移已经保存了的数据?能平滑过渡吗? (以one Topic-many Reply 为例)。 |
21
keakon OP 1. 使用task queue。一个实体保存成功后创建另一个task来更新下一个实体。文档里好像有个例子。
2. 实体一旦保存到数据库,它的实体组关系就不能变更了。因此你只能下载所有实体,删除所有实体,然后在上传时通过设置key的parent来构造实体组。 |
22
c 2010-11-17 20:27:57 +08:00
|