论坛首页 Java企业应用论坛

ORM其实是在映射网络模型和关系模型,OO的关系模型无需映射,且更简单高效

浏览 23733 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-01-10  
complystill 写道
firebody 写道

首先,我觉得楼主说得“关系模型”和 “网络模型”似乎不存在明显的界限,我更加愿意把这两个模型当作设计设计领域模型的结果。 或许这两个名词根本不存在。  为什么这样说呢? 因为我看到这段话:

引用
网络模型 中没有对应于 婚姻关系 的信息载体, 是通过两个对等的引用来表达: 一个 男人 的 妻子 引用 指向另一个 女人; 而这个 女人 的 丈夫 引用必须也指向这个 男人. 所以结婚的操作是同时设置这两个引用, 离婚的操作是同时清除这两个引用. 引用对的 原子对等性 要由应用程序来保证, 这在并发环境中每个地方都需要仔细的使用资源互斥.

关系模型 中, 婚姻关系 是一个专门的对象, 结婚操作就是创建这个对象, 离婚操作就是删除这个对象. 如果夫妻双方需要保存到对方的相互引用, 这个引用也是由 数据库管理系统 去维护的, 并发控制也完全由数据库系统管理.


从上面这段话来看,婚姻关系 在建模设计里面似乎是一个设计的结果,这个和模型名次没有更多的关系。 通过引用 和 通过一个专有的类 来表示建立婚姻。 这个设计是领域模型的不同设计的结果,这个结果和具体的需求又关系,和 “网络/关系模型”没有关系。


至于说 关系之间的自动维护,这个便利如果可以轻松获得那么还是很有好处的,不过这个好处带来的优势似乎并不是很大,在项目开发里面,特别是ERP开发里面,分析 这种 “关系之间的关系(比如举个例子来说, 比如婆媳关系, 为什么你的母亲是你妻子的婆婆, 而你妻子是你母亲的儿媳呢? 是因为你和你妻子存在婚姻关系. 假设你和你妻子离婚的话, 那婆媳关系则自动解除)”的工作是占据领域模型分析工作很大比例的一部分,而得到这个分析结果 再依次关系建立 关系维护逻辑的工作量则不是很大,需要的仅仅是明确的方法,至于你提到的关系的自动维护,应该也是基于这个 领域关系的分析基础之上的。  所以,在OO开发里面,这种关系的自动维护 和 手工维护 的对比 似乎不是我们所主要关注的部分。

如果从最终可以解决的问题来说确实是殊途同归:
C++和Java都是面向对象的编程语言, 只要灵活熟练的掌握, 完全可以写出同样的程序功能.
网络模型 和 关系模型 也都是数据模型, 能够灵活熟练运用, 完全可以解决同样的问题.

有些细小的差别, 比如 C++ 里需要自己建 Mutex 或者 临界区, 手工 获取 和 释放; 而Java里一个 synchronized 块就搞定.
但是 线程安全 总是一个统一的 设计结果, 是由 需求 决定的, 和 开发语言 没有关系.

只讨论 OO 开发的话, 到底用 C++ 还是 Java 去写代码也不是主要关注的部分.


说到这点 ,比较“一个明确意义的方法“ 和 “需要配置关系之间的关系的声明“,不知道这两者之间工作量差别是否很大? 当然还有一个额外的需求,希望“关系之间的关系的声明“和需求的分析结果一样直白易懂,至少清晰的代码还是可以达到这个要求的。  另外,也还希望加上可测试性的要求。希望不自动化到我得到数据库里面去验证结果就好了。
0 请登录后投票
   发表时间:2007-01-10  
msg db 'Hello$'
 mov dx, offset msg
 mov ah, 9
 int 21h
 mov ah, 4Ch
 int 21h

这个非常明确: 调用 DOS 系统功能显示一个字符串.
汇编一下可以直接测试不需要 CRT, 用 debug 写个 .com 连汇编都可以省了, 甚至直接在 debug 里逐句执行都可以.

#include <stdio.h>
int main(int argc, char** argv)
{
 puts("Hello");
 return 0;
}

这个要包含头文件, 写 main 函数, 还要先编译成 .obj, 再链接成 .exe, 最后在 CRT 的环境下才能执行测试. 在DOS环境下完成功能的最终还是差不多的几条指令.


综合来看两种途径同样去显示一个字符串, 工作量差别也不大.
...
感觉很多差别是系统复杂度导致的, 量变引起质变.

东西少的时候, 可以看到 "HOW", 觉得明白, 心里也踏实.
太多了以后, 可能对相同层面的问题, 就会更愿意只关心 "WHAT", 把实现 "分包" 给专门系统去处理.
0 请登录后投票
   发表时间:2007-01-10  
complystill 写道
msg db 'Hello$'
 mov dx, offset msg
 mov ah, 9
 int 21h
 mov ah, 4Ch
 int 21h

这个非常明确: 调用 DOS 系统功能显示一个字符串.
汇编一下可以直接测试不需要 CRT, 用 debug 写个 .com 连汇编都可以省了, 甚至直接在 debug 里逐句执行都可以.

#include <stdio.h>
int main(int argc, char** argv)
{
 puts("Hello");
 return 0;
}

这个要包含头文件, 写 main 函数, 还要先编译成 .obj, 再链接成 .exe, 最后在 CRT 的环境下才能执行测试. 在DOS环境下完成功能的最终还是差不多的几条指令.


综合来看两种途径同样去显示一个字符串, 工作量差别也不大.
...
感觉很多差别是系统复杂度导致的, 量变引起质变.

东西少的时候, 可以看到 "HOW", 觉得明白, 心里也踏实.
太多了以后, 可能对相同层面的问题, 就会更愿意只关心 "WHAT", 把实现 "分包" 给专门系统去处理.

问题的关键是 有些问题 理应 由 开发者关心,有些东西理应由框架或者语言来关心,正如你说的synchronized ,也正如你上面提到的语言级别的东西。
0 请登录后投票
   发表时间:2007-01-11  
嗯, 说到这里, 目前 基于关系数据库 的 对象持久问题, 主流方案一直是 应用程序(通过DAO) 或者 框架/容器(通过ORM) 来关心的.
而TOB呢, 是使得这个持久问题改由 数据库管理系统 来关心了, 应用程序 指定 What, 数据库 实现 How. 看来也可以作为一个宣传卖点了
0 请登录后投票
   发表时间:2007-01-11  
一个男人,一个女人结婚,就这么两个节点怎么会是网络模型呢?网络模型用数据结构来表达应该是图吧,没有很多节点用的着搬出“图”这种东西吗。两个点的连线就只有一条而已,什么结构都能称上,关系数据库是一种表达方式,把实体和关系存储成表的样子,对象也是一种表达方式。对于简单的两个节点都很容易表达。
我觉得网络的样子应该是:1级节点 有N个2级节点,2级节点有N个3级节点,依此类推,层次可能是比较深的,无法预知的;如果节点的父节点只有一个,那就是树形结构,是比较简单的网络,用对象也比较容易表达,如果父节点有多个,就比较麻烦了,关系数据库和对象都挺难表达出来,不知道tob怎么处理这种问题。
0 请登录后投票
   发表时间:2007-01-11  
eyejava 写道
一个男人,一个女人结婚,就这么两个节点怎么会是网络模型呢?网络模型用数据结构来表达应该是图吧,没有很多节点用的着搬出“图”这种东西吗。两个点的连线就只有一条而已,什么结构都能称上,关系数据库是一种表达方式,把实体和关系存储成表的样子,对象也是一种表达方式。对于简单的两个节点都很容易表达。
我觉得网络的样子应该是:1级节点 有N个2级节点,2级节点有N个3级节点,依此类推,层次可能是比较深的,无法预知的;如果节点的父节点只有一个,那就是树形结构,是比较简单的网络,用对象也比较容易表达,如果父节点有多个,就比较麻烦了,关系数据库和对象都挺难表达出来,不知道tob怎么处理这种问题。

"如果节点的父节点只有一个,那就是树形结构,是比较简单的网络"
-- 这个是 层次模型(Hierarchical Model), 在网络模型前被提出来的.
"如果父节点有多个,就比较麻烦了"
-- 这个就是 网络模型(Network Model) 被提出的原因, 就是为了在 层次模型 的基础上解决多父的问题.

这些数据模型问题基本都是在上世纪六,七十年代集中讨论的, 要查点古董资料才能搞清楚的.

如果对很理论性的东西不是很感兴趣, 关注实用实践更多一些, 可以时常留意看看

http://tob.ableverse.org/pattern.html

这个地方, 陆续会有面向不同应用的新持久模型样板代码出来.

如果目前有兴趣又有时间, 可以下载

http://wow.dev.java.net

的代码研究看看基于 TOB 对网状数据结构的建模处理.
0 请登录后投票
   发表时间:2007-05-22  
这里讨论实在令人耳目一新!
不过这里的概念实在有点难理解(可能今天心情不畅,看到这些东西差点心肌梗塞:-))
首先对 歆渊 表示一下支持,为了更好的理解你的想法,我自私提一个你可能解释百编的问题,
(你举的那个婆媳,丈夫例子对我来说还是太复杂了点。)

我的例子是:
10,000个group,
1000,000个user
他们之间是多对多的关系,

你能否简单介绍一下用你的框架是怎么解决下面的问题:
1,怎么添加,更新,删除一个group或user?
2,怎么添加,更新,删除group和user之间的关系?
3,怎么根据特定的条件查询group,user,以及一个group下面的user或一个user属于的group?
4,怎么控制并发操作?
5,怎么load或save内存中user和group的实例(或数据)?

最好仅仅介绍你的方案是怎么做的,先不要介绍你这样做的理论根据,也不要涉及关系数据,ORM,以及面向对象的数据库是怎么做到这些的。

非常期待你的回答!
谢谢!
0 请登录后投票
   发表时间:2007-05-25  
lihy70 写道
这里讨论实在令人耳目一新!
不过这里的概念实在有点难理解(可能今天心情不畅,看到这些东西差点心肌梗塞:-))
首先对 歆渊 表示一下支持,为了更好的理解你的想法,我自私提一个你可能解释百编的问题,
(你举的那个婆媳,丈夫例子对我来说还是太复杂了点。)

我的例子是:
10,000个group,
1000,000个user
他们之间是多对多的关系,


这里首先会涉及到一个内存策略的问题, TOB是为大内存设计的, 假定自己运行在内存比较充裕的环境下.
但TOB并不是像传统内存数据库那样要把所有数据都加载进内存, 而是加载一个对象时要把所有和它物理连接的对象全部加载进内存.

拿这里的例子来说, 假如其中5,000个group只包含500,000个user, 而且因为这些user交错隶属于这5,000个中不同的group, 导致5,000个group和500,000个user都直接或间接关联, 形成一个封闭的对象图. 那么这时候如果应用需要其中某个group或者user对象的话, 这所有5,000个group和500,000个user就必须同时被加载进内存. 不过另外不相干的5,000个group和500,000个user就不需要加载了.

当然也有可能10,000个group和1000,000个user全部有关, 这种情况下就要看服务器内存是否同时容得下所有这些对象了, 如果内存没有那么大, 就不能用TOB的物理连接来设计持久类方案了, 否则铁定会 OutOfMemoryError.

这时可以通过逻辑连接, 既用一个数值型的持久字段来存储相关对象的 Object ID, 需要的时候以这个 ID值 向TOB要对象实例. TOB用Tree Table来处理这种请求, 对象已经加载情况下的性能损失可以基本忽略不计. 不过逻辑连接就享受不到TOB的ORK模型的好处了, 要自己实现相关对象的获取和一致性维护. 不过对不常用数据, 逻辑连接也不失为一个有效方法, 比如 WoW 保存信息节点的历史版本对象时就是用这种方式.


后面考虑这里问题的解决方案时我们就假定服务器内存足够大, 能够装下最大的 group-user 拓扑图. 这是能够最大限度发挥TOB优势的case.

lihy70 写道

你能否简单介绍一下用你的框架是怎么解决下面的问题:
1,怎么添加,更新,删除一个group或user?

添加:
 Group g = tob.birth(new Group("G 1"));
 User u = tob.birth(new User("Compl", "Ableverse"));

更新:
给 Group 和 User 类上修改持久字段的实例方法加上一个 @Writing 标注, 然后需要的时候直接调用就好了.
public class User extends TheObject
{
  ...
  @Writing
  public void setCompany(String c)
  {
     this.company = c;
  }
}

User u = tob.get(123);
u.setCompany("JavaEye");
tob.commitAllTransactions();

删除:
用从 TheObject 公共基类继承来的 void die(); 方法
User u = tob.get(123);
u.die();
tob.commitAllTransactions();


lihy70 写道

2,怎么添加,更新,删除group和user之间的关系?

定义一个关系类:
public class Membership extends TheRelation
{
  protected Tie<Group> group;
  protected Tie<User> member;

  public Membership(Group g, User u)
  {
    this.group = new Tie<Group>(g);
    this.member = new Tie<User>(u);
  }

  public Group getGroup()
  {
    return group == null ? null : group.o;
  }

  @Retying ("group")
  public void changeGroup(Group g)
  {
    this.group = new Tie<Group>(g);
  }

  // similar for memeber
  ...
}

然后添加:
Group g = ...;
User u = ...;
Membership m = tob.birth(new Membership(g, u));
tob.commitAllTransactions();

更新:
Group g = ...;
Membership m = ...;
m.changeGroup(g);
tob.commitAllTransactions();

删除:
Membership m = ...;
m.die();
tob.commitAllTransactions();


lihy70 写道

3,怎么根据特定的条件查询group,user,以及一个group下面的user或一个user属于的group?

特定的条件利用SQL, TOB根据持久类的持久字段生成用于拼装SQL的条件类. 本质还是SQL, 就不举例了.
不过表里的总数据量超大, 单个关联对象的数据量较小, 或者SQL条件异常复杂时, 可能自己遍历KinSet集合用Java代码进行判断筛选的方案效率更高. 比如 WoW 的操作权限校验过程.

user的groups和group的users通过定义KinSet来实现:
public class User extends TheObject
{
  @IAm("member") // optional since no ambiguity to clearify
  @TheyAre("group") // optional since no ambiguity to clearify
  private KinSet<Membership, Group> groups;

  public List<Group> listGroups()
  {
    List<Group> gs = new ArrayList<Group>(groups.size());
    for(Kin<Membership, Group> gKin : groups)
      gs.add(gKin.getO());
    return gs;
  }
}

// users kin for class Group is similar


lihy70 写道

4,怎么控制并发操作?

TOB在底层控制事务, 目前是绑定到当前线程. 应用只需要在完成单元操作后调用 tob.commitAllTransactions(); 就可以了. TOB可以配置为通过 悲观锁 或者 乐观锁 进行冲突防止和仲裁. 应用需要做的就只是给自己的持久类上进行排他读取的方法加上 @Reading 标注, 修改持久字段的方法加上 @Writing 标注, 持久关系类上修改Tie字段的方法加上 @Retying 标注.

lihy70 写道

5,怎么load或save内存中user和group的实例(或数据)?

不需要显式的load或save.
通过OID或者查询获得持久对象时, TOB把它加载好了才返回给应用.
如果调用了某个对象标注为@Writing的方法, 则 tob.commitAllTransactions(); 的时候就会保存它.


另外 tob.startNewTransaction(); tob.commitCurrentTransaction(); tob.commitAllTransactions(); 以及相应的 rollback 方法, 一般在应用框架级别上做就可以了, 应用功能代码鲜少需要直接跟这些打交道.

还有就是如果 rollback 了, 对象的持久字段会自动恢复到事务之前的的取值, 应用如果保存了对象引用还是继续有效, 指向正确的对象, 不需要重新查询或者什么特殊操作.
0 请登录后投票
   发表时间:2007-05-27  
楼主的设想在一些商业应用上已经有了先例,Ariba公司的AML(Ariba MeteData language)与相对应的缓存模型定义完全完全将Java对象和关系数据契合在一起,将大量数据放在内存中,支持继承、复写、扩展、引用,完全将数据库层和Java对象层隔离出去。进行开发时,不需要考虑数据库层,也不需要考虑Java对象层,无需关心对象的创建、释放、提交等操作,对象只有在显式销毁时才被写入数据库,支持并发、效率也很高
0 请登录后投票
   发表时间:2007-05-27  
litchi 写道
楼主的设想在一些商业应用上已经有了先例,Ariba公司的AML(Ariba MeteData language)与相对应的缓存模型定义完全完全将Java对象和关系数据契合在一起,将大量数据放在内存中,支持继承、复写、扩展、引用,完全将数据库层和Java对象层隔离出去。进行开发时,不需要考虑数据库层,也不需要考虑Java对象层,无需关心对象的创建、释放、提交等操作,对象只有在显式销毁时才被写入数据库,支持并发、效率也很高


有没有公开的网站包含更多信息的? google了一下没找到官方网站和活跃的讨论区, 你这个描述有点含糊:

"进行开发时,不需要考虑数据库层,也不需要考虑Java对象层"
那写程序时关心什么?


"无需关心对象的创建、释放、提交等操作"
连 new 对象都不用了? 确实想像不出这个程序是怎么编的了.


"对象只有在显式销毁时才被写入数据库"
那就是说数据库里只保存历史废品, 而且没销毁之前如果 power failure, 那数据就都蒸发了?


PS: 我觉得可能这个产品确实是很好的, 但是你这里的描述似乎不准确.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics