2005-10-24

about SQL, ORM, DSL

SQL, ORM, DSL

语言越高级,可读性就越高。DSL通常用作规则引擎语言,是给非程序员的业务人员使用的。
SQL是一种类似英语的非常友好的 Domain Specific Language。可读性非常高。
是比 python, ruby, Haskell 等解释脚本语言更高级的语言。而这些解释脚本语言是比 OO 语言(如 Java, C# 等)更高级的语言。
对于数据库查询来说,SQL 比 Java API 友好简单许多,所以我一直反对用 Java Query Criteria API 代替 SQL 拼接。
一个很奇怪的现象是,很多人都认为,SQL很低级,不够OO, 不够高级。
也许我们习惯了Java API的OO思维。

Cat cat = CatDAO.findById(…); /// java api

Select * from cat where id = ? /// sql

SQL的可读性就这么差? 真是具有讽刺意味。我们的OO教育太成功了。以至于OO程序员很难看懂 给普通业务人员使用的SQL语言。

关系数据库出现之前,其他类型的数据库(网状等)因为模型非常复杂,只用SQL无法表达其中复杂细微的需求。
关系数据库论文中,提出了简单的二维表模型,以至于简单易读的SQL就可以表达几乎所有的数据库需求。虽然关系数据库很慢,由于友好的SQL,后来慢慢成为主流。
EJBQL, HQL, OQL 确实给我们带来了80%简单需求的方便,但是在一些高级需求方面,也带来了不少烦恼。Inner join, outter join, join or not join, fetch or not fetch。在这些地方的具体配置上,又要具有 关系数据库的思维。虽然差强人意,但总有不伦不类之嫌。

多语言无缝集成
.net 的多语言协作的思想。各种适合本域的语言,能够共同使用,彼此之间交织,而能共同合作。所以,DSL, LOP (Language Oriented Programming) 提倡每个领域要有自己的 领域语言。
目前的SQL + Java 的主要问题是,两种语言经常混同于一个文件中,而没有分离出来。(HQL,OQL又何尝不是如此?)
我想,假如一种异类语言不是 嵌入在 其他语言的 源文件中,而是分开的独立的源文件,那么,这是很好的编程模式。也是未来的趋势。
SQL + OO + FP + other DSL….
评论
partech 2005-11-18
age0 写道
上纲上线到面向过程了,还不至于吧,事实上即使是OO设计,也同样属于“结构化”的范畴之内,只是结构更复杂而已,只有DSL才可以摆脱结构化的嫌疑。


是喔。按照你的理论下面这样不是更好?

Service ----->SQL------->DBTable

要个OO的遮羞布干啥?
buaawhl 2005-11-18
DSL 的一个重要特点,应该是,在该领域 学习成本 远远低于 通用语言。而且,该领域 覆盖的面积足够大。这样,收益 才会大于 成本。

LOP 很容易滥用 DSL。不应该每个领域都使用DSL,而是在几个重要的面积广大的领域中,使用DSL。
age0 2005-11-18
partech 写道

我认为OO和SQL都是很有用的,但是需要看所处的环境,SQL就像它名字本身预示的一样,擅长于查询。OO更适合于完成复杂的业务逻辑。如果你认为SQL比OO能更好的处理业务逻辑,那么合理的推论就是纯SQL的程序会比OO的程序写出来的程序好。能告诉我,你现在就是这样做的吗?或者打算这样做?


我推崇的是DSL,当然对SQL也很赞赏,但是DSL并不是只有SQL一种,也并不仅局限于数据库领域。SQL在数据库领域的表现大家都有目共睹,那么在软件开发领域我们是不是也能够提供类似的DSL呢?我们不指望DSL能够解决所有问题,如果DSL能够解决所有问题,那么它将会成为另一个通用语言而非DSL。但是只要DSL能够以便利的方式解决软件开发中遇到的一部分通用问题,依然能够将开发效率提升一个层次,最Dirty的部分还是留给通用语言,这样的DSL我想也不是不可实现的。
age0 2005-11-18
partech 写道
你这不就是当初面向过程的做法吗?面向对象的思想当初是怎么战胜面向过程的思想,你大概忘了。恰恰正是因为结构化的面向过程不适合于复杂的系统阿。

SQL其实同你说的这种间接关联是不同的,SQL是面向结果而不是面向过程的,这也是它能被非程序员使用的重要原因。

我认为OO和SQL都是很有用的,但是需要看所处的环境,SQL就像它名字本身预示的一样,擅长于查询。OO更适合于完成复杂的业务逻辑。如果你认为SQL比OO能更好的处理业务逻辑,那么合理的推论就是纯SQL的程序会比OO的程序写出来的程序好。能告诉我,你现在就是这样做的吗?或者打算这样做?


上纲上线到面向过程了,还不至于吧,事实上即使是OO设计,也同样属于“结构化”的范畴之内,只是结构更复杂而已,只有DSL才可以摆脱结构化的嫌疑。

frankensteinlin 2005-11-18
每一种语言都有一个问题域,面向对象的语言如:java ,C#,c++等,是通用语言,它所要描述的问题域非常广泛,几乎是不限定的,对象可以狭义的理解为自然语言的名词,也就是说java等语言可以自己描述一个问题域,阐述这个问题的边界,它的性质,它的行为,比如 :
class persion {
public void eat()

这里它描述的问题域就是人,他定义的边界就是研究吃这个行为,其他的人的行为就不管了。
从这一点说java等语言可以说是“元语言”。

SQL 就不一样了,它的问题域很清楚,就是关系型的数据操作,他研究的就是表啊,记录啊,它不需要自己定义边界,他有了自己的名词,并且建立了自己的语法,规范了自己的行为。可以说它是建立在“元语言”之上的专用领域语言。

你可以用元语言来解释SQL语言,SQL语言可以用java来实现,也可以用C#来实现,它本身比java等语言更专。就这一点说它已经超越过程化语言,或者对象语言了。它是用这些元语言建立起来的一种领域语言!

有个问题:中国话是面向对象的还是面向过程的?
partech 2005-11-17
age0 写道

我的意思是直接联系改成间接联系,改变的只是方式而已,联系还是存在的,并没有被割断。

OO的核心价值之一是封装,将数据和操作封装在一个类里面我称之为直接联系,但是如果将数据和操作单独封装,并在第三个类里面维护数据和操作的关系则称为间接联系,当然,这只是针对复杂的体系设计而言。

而在DSL里面,对象的概念被大幅弱化,数据和操作之间的关系会以另一种全新的方式展现,如何以DSL方式重新演绎数据、操作以及它们之间的关系是很值得探讨的。

你这不就是当初面向过程的做法吗?面向对象的思想当初是怎么战胜面向过程的思想,你大概忘了。恰恰正是因为结构化的面向过程不适合于复杂的系统阿。

SQL其实同你说的这种间接关联是不同的,SQL是面向结果而不是面向过程的,这也是它能被非程序员使用的重要原因。

我认为OO和SQL都是很有用的,但是需要看所处的环境,SQL就像它名字本身预示的一样,擅长于查询。OO更适合于完成复杂的业务逻辑。如果你认为SQL比OO能更好的处理业务逻辑,那么合理的推论就是纯SQL的程序会比OO的程序写出来的程序好。能告诉我,你现在就是这样做的吗?或者打算这样做?
age0 2005-11-17
kuky 写道

age0的汽車的例子我覺得把數據庫看成倉庫可以直接用sql語句,總之是要看你怎麽看待數據庫的,有些人把它看成倉庫,有些人把它看成直接能用的對象,所以差異也就產生了,倉庫的辦事效率缺點是明顯的,這讓我想起了各個汽車公司都在搞的零庫存計劃,還有很多家大公司都在說的寧願少生産也堅決不庫存的口號,其中的差別他們可能領悟得更多一點。


我想你有点误会了,零库存指的是产品的零库存而不是生产原料的零库存,对于汽车公司来说每生产一台汽车立刻就能卖出去当然是最理想化的目标,但如果是汽车零件零库存的话就有问题了,零件供应一出问题马上就会停产,这是要极力避免的。

数据库则复杂一点,既要存储原始数据又要存储结果数据,虽然Domain Object的关系复杂多变,是Dirty的根源,但终归会在存储的时候被统一为纯粹的二纬关系,极大简化了存取操作。事实上我也是SQL的坚定支持者,所写的ORM机制也仅仅是SQL的生成辅助工具,SQL作为纯粹的高层次抽象DSL,是不应该被Domain Object的Dirty所牵连的。
buaawhl 2005-11-17
kuky 写道

不過buaawhl你說的那些都不是重點,就像判斷髒數據和cache生成的查詢語句一樣不是重點,重點在relations的處理上,什麽時候生成帶JOIN的sql,什麽時候生成不帶JOIN的sql,這才是最難的部分,你不會是每次生成的sql都是一大堆left join弄得莫名其妙奇慢無比生成的log也永遠看不懂象hibernate一樣把?


问题在于,为什么要“生成SQL”?

Lightor 不生成 SQL, 直接使用SQL。
对于relation 的处理,Hibernate 已经给出了很好的实现思路。我在前面也描述了。lazy load, batch size. 为什么要学那种 join , left join 呢?

---
join , left join 只有很少数的情况,才是应该使用的。而那少数情况下,几乎所有的ORM都无法支持,除了lightor。

select a.*, b.* from a, b where....

为了处理速度,一下子join 出来所有相关的数据,one by one 处理result set结果集,只有这种情况才是 join, left join的最佳使用场合。

这时候,需要把每个 result set 都one by one映射为 a, b object.
只有lightor支持这种用法。

其余的情况,如果不是为了one by one 依次处理,那么一般都是 分页查询,进行显示。需要选出结果集中的 某一段范围。
那么就有一个问题,是先 join关联 ,然后再 分段,还是先分段,再join 关联?
先 join关联 ,然后再 分段,显然慢;先分段,再join 关联,要快。

至于是否需要join, 还是否用到cache。用到join, 会影响cache的使用。
frankensteinlin 2005-11-17
其实这个问题看看他们的名字就知道了:
面向对象的处理;关注点是一个一个对象,它在处理单体的时候比较灵活。
SQL是处理关系的,对于群体的关系处理比较灵活。

这就是现实世界的波性和粒性, orm么就是有波粒二象性,更偏重于粒性,借助hql 能展现出更多的波性
age0 2005-11-17
partech 写道
赫赫,早看过了。看不出,同你数据比逻辑稳定因此最好分离他们的观点,有啥直接关系?
并且,单独看待数据和操作,是完全没有意义的。数据意味着操作,操作也意味着数据。


我的意思是直接联系改成间接联系,改变的只是方式而已,联系还是存在的,并没有被割断。

OO的核心价值之一是封装,将数据和操作封装在一个类里面我称之为直接联系,但是如果将数据和操作单独封装,并在第三个类里面维护数据和操作的关系则称为间接联系,当然,这只是针对复杂的体系设计而言。

而在DSL里面,对象的概念被大幅弱化,数据和操作之间的关系会以另一种全新的方式展现,如何以DSL方式重新演绎数据、操作以及它们之间的关系是很值得探讨的。
partech 2005-11-17
age0 写道
partech 写道
不如说,直接使用SQL操作数据最灵活。要啥控制类,实体类?


先去读读文章,积累点背景知识。

http://martinfowler.com/articles/languageWorkbench.html

赫赫,早看过了。看不出,同你数据比逻辑稳定因此最好分离他们的观点,有啥直接关系?
并且,单独看待数据和操作,是完全没有意义的。数据意味着操作,操作也意味着数据。
age0 2005-11-17
partech 写道
不如说,直接使用SQL操作数据最灵活。要啥控制类,实体类?


先去读读文章,积累点背景知识。

http://martinfowler.com/articles/languageWorkbench.html
partech 2005-11-17
age0 写道
就我的经验而言,将业务逻辑及业务数据的直接联系变更为间接联系会大幅降低系统的藕合度,适得业务系统更加灵活。

不如说,直接使用SQL操作数据最灵活。要啥控制类,实体类?
buaawhl 2005-11-17
kuky 写道
哎呀,話説重了

其實我這話只是因爲看到了buaawhl說的Lightor (ORM), 因爲自己做過orm框架, 對orm有一些自己的領悟, 覺得沒有必要為了ORM而去ORM, 並不是針對數据庫犯下的錯, 我也不想在這裡同別人爭論這是否是個錯, 我自己並沒有做出一個完全使用api而不使用sql的數據庫系統, 所以也沒資格去批評oracle, 我只是個務實者, 所以我還是只做了個orm框架, 二維結構本身並沒有錯, 因爲對於人來説最易于理解, 但由二維結構引出的關係問題就確實是一個問題, 不知道huaawh的框架裏的這個問題有沒有很好的解決, 我是想了各種方法, 在理想的思想和現實的速度中間取捨, 最後採用了折中的手段, 速度ok了, 易用性也ok了, 回過頭來看看自己寫的代碼, dirty, 好在生成的代碼還馬馬虎虎, 派得上用場, 但偶爾反思的時候, 縂覺得根據我最初的意圖來看, 我走偏了, 偏得很遠了..................所以有點鬱悶, ORM並不是想象中的那個完美的東西, 它只是讓我想起了馬克思描述的資本主義初期階段, 只是個要承擔很多dirty的任務, 又要彌補sql的各種缺點的很badSmell的苦工而已.........


ORM的这些问题都是存在的。
Java 要用 Object, 数据库要用 SQL 和 table。而我们要用 java & database.
我们可以直接用Java 调用JDBC, ResultSet, SQL 等。但是这种用法在java里面造成可读性变差,造成了Domain Pollution 的情况。HTML 和 Server side script Code 的情况。
ORM就是来作做这个dirty job的,成为一个Object 和 table 的桥梁。

我花了很多功夫改造Lightor,达不到完全满意的效果,只是尽量达到我理想中的目标。
思路和PEAA中阐述的类似,All glories belong to Mapper. 所有的荣耀归于Mapper.

1. Use Cases
[code:1]
persister.save( pojo ){
Mapper mapper = getMapper( pojo );
mapper.save( pojo );
}
[/code:1]

2. Life-cycle POJO.
如同iBatis。Lightor 不在任何时候, 篡改用户的Domain Ojbect代码。Hibernate动态期间篡改,JDO静态期间篡改。

3. Code Generation
Mapper的实现,可以像 iBatis 那样使用reflection 。出于速度和功能方面的考虑,使用了静态 Code Generation 。
这个Code Generation 完全是用来generate mapper的。而不是用来generate data object。这和其他 ORM 都不同。基本上所有的ORM都要求generate data object。比如Hibernate generate PO at runtime, JDO enhance POJO as PO statically. 其他很多ORM干脆就直接generate PO instead of POJO。
Lightor 只产生Mapper。这意味着用户的代码无论是运行期,还是编译期,完全是干净的。这就避免了 这个层次的 domain pollution.
Mapper source, mapper class jar。都可以分离加入 project。用户完全可以debug mapper code。

Note: 在这个层次上,iBatis 也是非常干净的。

4. 关联 association.
由于使用Code generation, 所以,可以实现很多比较强大的功能。比如association。
Lightor的关联实现思路,基本跟随hibernate。
hibernate根据xml 动态修改POJO,建立联系。
lightor只是把这动态生成的关联代码,放到了mapper 里面。并且把API暴露出来,而不是config。
如果需要关联,要在DAO代码里面写,
assocatiate( forums, "lastTopic");

forums 是一个list, 里面是Forum Object, 每个Forum 有一个lastTopic property. 关联到外部的Topic Object。
调用了
assocatiate( forums, "lastTopic");
就意味着一下子取出所有的相关lastTopic, 然后分配到对应的forum上。这个工作是在 对应的mapper里面做的。
在关联方面,hibernate 采取config, 动态生成。lightor 只是 hibernate 的静态化,API化。这是为了容易debug,和能够明显的控制。

Lightor的缓存思路也是基于hibernate缓存思路的优化,我以前就写过这方面的文章。这里不多说了。

4. SQL 和 Java Code 的分离

首先,声明一下,我是反对HQL,OQL, linkQ 的。这种属于 语言级别的 domain pollution。更是根深蒂固,难以消除。我推荐完整的可以直接在SQL Client 调试的Pure SQL。

Java Code 里面夹杂 SQL,或者SQL里面夹杂着Generate Script,虽然不如 HTML 里面夹杂 server side script 那么明显的domain pollution, 但还是带来了一些不便和不快。

我采用的方法是,把所有的SQL 字符串资源都从 Java Code 剥离出来,放在一个对应的 xml 或者 text 文件里面。
这样,这些SQL 就可以直接放到 sql client 工具里面进行验证和调试。
对于动态SQL拼装,我采用fastm来处理。

select * from topic
where forum_id = {param:forum.id}

// BEGIN DYNAMIC: replyLimit
and reply_count >= {text:replyLimit}
// END DYNAMIC: replyLimit

// BEGIN DYNAMIC: beginDate
and post_time >= {param:beginDate}
and edit_time >= {param:beginDate}
// END DYNAMIC: beginDate

// BEGIN DYNAMIC: endDate
and post_time <= {param:endDate}
and edit_time <= {param:beginDate}
// END DYNAMIC: endDate

传给这段template一个POJO, 比如一个java bean, 或者 一个map.
会返回一个 SQL 和 Parameter 列表。

比如,sql 是
select * from topic
where forum_id = ?
and reply_count >= 20
and post_time >= ?
and edit_time >= ?
and post_time <= ?
and edit_time <= ?

参数列表是 { 1, date1, date1, date2, date2 }

这样能够尽量减少Java里面拼装SQL的逻辑。并且SQL里面也不出现任何logic,而只有 分支和参数描述。

----
以上通过种种手法,避免domain pollution。

Java 的归 java , database 的归 database。
两者的交叉减少到最少。
age0 2005-11-17
kuky 写道
哎呀,話説重了

其實我這話只是因爲看到了buaawhl說的Lightor (ORM), 因爲自己做過orm框架, 對orm有一些自己的領悟, 覺得沒有必要為了ORM而去ORM, 並不是針對數据庫犯下的錯, 我也不想在這裡同別人爭論這是否是個錯, 我自己並沒有做出一個完全使用api而不使用sql的數據庫系統, 所以也沒資格去批評oracle, 我只是個務實者, 所以我還是只做了個orm框架, 二維結構本身並沒有錯, 因爲對於人來説最易于理解, 但由二維結構引出的關係問題就確實是一個問題, 不知道huaawh的框架裏的這個問題有沒有很好的解決, 我是想了各種方法, 在理想的思想和現實的速度中間取捨, 最後採用了折中的手段, 速度ok了, 易用性也ok了, 回過頭來看看自己寫的代碼, dirty, 好在生成的代碼還馬馬虎虎, 派得上用場, 但偶爾反思的時候, 縂覺得根據我最初的意圖來看, 我走偏了, 偏得很遠了..................所以有點鬱悶, ORM並不是想象中的那個完美的東西, 它只是讓我想起了馬克思描述的資本主義初期階段, 只是個要承擔很多dirty的任務, 又要彌補sql的各種缺點的很badSmell的苦工而已.........


我的看法则相反,relational database的成功正是因为纯粹,无论业务对象的关系有多复杂,在数据存储的时候只有二维关系,数据库顾名思义就是存储数据的仓库,关心的只是如何简单快速的存取数据而已,至于数据之间的关系有多复杂,那跟如何存储数据没有任何关系。举个简单的例子,汽车装配厂和汽车零件仓库,通常零件都是存放在仓库,只有装配的时候才会取出来送到装配厂进行装配,理所当然的,汽车零件在仓库和装配厂的摆放方式是不可能一样的。OO没有错,RDB也没有错,错的只是ORM而已。软件存在的目的就是要解决问题,为各种各样的问题提供解决方案,但是软件开发本身并不是提供解决方案,只是作纯粹的翻译工作。业务解决方案实际上是由行业专家及客户提供的,不过解决方案由谁提供倒不是什么大问题,最严重的问题莫过于问题域的不稳定性。简单划分一下,一个完整的业务可以分割为业务逻辑及业务数据两部分,相较而言,业务数据要比业务逻辑稳定一点,变化最多的是业务逻辑,只要将现有数据依照特定逻辑组织一下就可以形成一个全新的业务对象。这样会导致一个非常严重的问题,随着业务逻辑的不断变化,Domain Object也只能产生相应的变化,如果Domain Object之间的关系比较复杂甚至会引发连锁反应。对于ORM来说,由于将O和R捆邦在一起,O产生的变化毫无疑问将会直接牵连ORM。从OO设计的角度来看,提供一个直接的ORM看起来确实是很美好,但从整体而言,由于Domain Object的复杂性及多变性,ORM注定只能是Dirty的。就我的经验而言,将业务逻辑及业务数据的直接联系变更为间接联系会大幅降低系统的藕合度,适得业务系统更加灵活。
庄表伟 2005-11-16
kuky 写道
庄表伟 写道
如果所有的应用都围绕数据库的二维表来展开,只有Data-Relation,没有Object,世界真是会清静好多。



這話怎麽看上去和你在DJ裏宣揚的哲學不太一樣?


正是一脉相承的呀。

要打破OO的静态封装,变成动态封装,自然是语言级的事情。

而要保护数据,RDBS级的触发器,其实也和我的DJ中的事件触发机制,是类似的。

所以,如果能够在数据库级提供一种新的SQL,想来应该会更加自然的吧。
庄表伟 2005-11-16
kuky 写道
我對sql的看法剛好相反, 我自己也做過ORM框架(雖然我超級不喜歡ORM這個詞),也是代碼生成的,做出來之後我慢慢地領悟到,sql是軟件發展的過程中犯的最大的一個錯誤。如果數據庫一開始就是使用API的方式,Object和Data可以天生就在一起,今天的OO開發可以做到真正的Unified,世界上也永遠不會有ORM這個詞,ORM天生就是畸形的,不過它的畸形是因爲有這麽一個只顧着自己靈活的sql!沉迷于ORM的人們,請你們自己思考一下我的話。


我也叫一声老大!

我的看法正好和你相反。

如果所有的应用都围绕数据库的二维表来展开,只有Data-Relation,没有Object,世界真是会清静好多。
buaawhl 2005-11-16
kuky 写道
我對sql的看法剛好相反, 我自己也做過ORM框架(雖然我超級不喜歡ORM這個詞),也是代碼生成的,做出來之後我慢慢地領悟到,sql是軟件發展的過程中犯的最大的一個錯誤。如果數據庫一開始就是使用API的方式,Object和Data可以天生就在一起,今天的OO開發可以做到真正的Unified,世界上也永遠不會有ORM這個詞,ORM天生就是畸形的,不過它的畸形是因爲有這麽一個只顧着自己靈活的sql!沉迷于ORM的人們,請你們自己思考一下我的話。


:idea: 老大

oracle 就是靠这个最大错误起家的,而且还在继续这个错误。
数据库大量使用在统计、报表、数据挖掘方面。
至于kuky老大 谈到的 database mis oo api, 只是数据库应用中的一块而已。

这个说法很有意思。
既然relational database 这么不适合软件开发,为什么软件开发要选择RDB作为存储介质?选文件api 不就得了?或者使用非关系数据库。
是谁的错?rdb的错,还是软件开发的错?
age0 2005-11-16
DSL已经是最高级别的抽象层次,落后的是现有的软件开发技术而已,假如有一天Intentional Software、Meta-Programming System、Software Factories甚至是Model Driven Architecture (MDA) 真的成功了,所有的ORM都是浮云。数据库操作是DSL,业务操作也是DSL,那时候才是真正的大一统。
frankensteinlin 2005-11-09
SQL是一种集合数据操作的语言,特别适合对面向关系的大量数据操作,微软的Linq就是想让c#在这方面添加优势。
java是一种通用语言,它的基础就是循环条件作为逻辑推理的等的基本语句。
拿着两种语言比简直就是关公战秦琼么!
完全可以用Java写个SQL引擎,两者不是同一类的东西,基础是不同的。

两者如何交互在hibernate里已经有很好的模式了:
form cat.class where id="aa"
通过java调用hibernate内置的语法分析其,将java的字符串解释成SQL,并且将SQL返回的结果解释成java的事列。

hibernate就是个翻译,其实各个领域的语言都有自己的优势,现在需要的就是要好的翻译,把他们粘合在一起。

当然,最好的是在同一个平台上。Linq就是想把它搬过来,一体化,降低开发的成本,(不需要翻译了)
buaawhl
搜索本博客
其他分类
存档
最新评论