分析一下 Java ORM 框架的原理,大家怎么看?

2020-12-15 12:45:59 +08:00
 Braisdom

Java 的 ORM 框架发展了很多年,一直存在各种各样的问题,相信大家的体会比我还要深,到底这是什么什么呢?我从两个角度来分析一下,大家看看对不对?

1 )语义表达的双重性

一个 Java Bean 的定义,只能表达一种语义,就是与其它相关的 Java 类相互协作实现一项特性,通常用于数据的载体,但不能表达数据库交互时的 SQL 的语义,两种内存的语义差异很大(例如:Java Field 在数据库中映射为 Column,一个 Column 可以进行排序、算术运算、比较运算等),很难通过 Annotation 进行描述,除非 Java 中增加新的特性,用于描述一个 Java Class 的多重语义。既然一个 Java Class 无法满足双重语义的描述,只能新增代码进行定义和描述,此时又出现重复代码和变更的一致性,通过 Maven 或 APT 形式生成,也会存在每次变更后,都需要重新运行任务,才能正常使用,使的开发过程变得更糟。

2 )语法一致性

Java 语法与 SQL 语法从语义上说基本是一致的,但表现形式不一样,例如:Java 中逻辑表达式:a && b 或者 a || b,而 SQL 中则是 a AND b 或者 a OR c,两种类型表达语义上一致,但语法上不能直接互换。同时,也无法 Java 对语义的解析和执行过程进行干预,也就导致了 Java 的表达式无法直接转换为 SQL 表达式,只能以字符串的形式进行拼接,通过对字符串拼接过程进行抽象和封装,形成一系列 API,这也就导致了简单的表达式变成若干 Java 方法的嵌套,严重影响了代码的可理解性。

ObjectiveSQL 完美的解决了上述两个问题,通过 Java 代码的动态生成和 Java 运算符重载等特性,有兴趣的同学可以发起挑战: https://github.com/braisdom/ObjectiveSql

4822 次点击
所在节点    Java
34 条回复
wangyanrui
2020-12-15 12:57:37 +08:00
支持一下楼主,简单看了一些 Readme,ORM 的程度弱于 JPA 之类,但是远强于 MyBatis,如果是个人开发的话,估计是熬了不少个通宵😂😂😂😂

另:JAVA 是面向对象的,RDBMS 不是面向对象的,这玩意就是个死结呀~
Braisdom
2020-12-15 13:06:18 +08:00
@wangyanrui 感谢兄弟,面向对象和数据库本质上是不冲突的,数据库的特性以对象关系型计算为基础,仅仅是一个数据存储和计算引擎,与语言的特性关系不是太大。
neochen13
2020-12-15 13:09:24 +08:00
老哥,我现在看到你就知道你想推广自己的东西

每篇都这样,越看越反感
wangyanrui
2020-12-15 13:09:37 +08:00
可能最后一句没描述清楚吧,我的意思是什么时候数据库支持面相对象了,就破费特了😂
Braisdom
2020-12-15 13:13:04 +08:00
@neochen13 兄弟对不住了,我也只是想写一点干货,也是我的理解,希望对你有价值,你可以忽略后面的链接


@wangyanrui 对象化的数据库很多年前就已经有人在尝试了,但也难以超越关系计算的理论,总是绕不开呀。
hantsy
2020-12-15 13:23:25 +08:00
好像有一个产品叫 ObjectDB,原生支持 JPA API 。
hantsy
2020-12-15 13:27:08 +08:00
@wangyanrui OR Mapping Mismatching 是个老话题了。JPA 主 OOP,不得不让数据库做一些妥协,比如 JPA 继承的设计,对应的表的结构不符合数据库的范式。
Braisdom
2020-12-15 13:35:08 +08:00
@hantsy 恩,不同类型的数据存储方式,和不同类型外部访问和计算方式,一直在挑战传统关系型数据,早些年 Google 为主发起的 NoSQL 系列数据库风头很盛。
我个人觉得,分久必合,合久必分,关系数据库统治数据库领域好多年了,在不同行业,不同数据和计算特征的领域会有新型的数据库出现,但能不能超越由关系数学这种高度抽象的概念衍生的关系计算模型就难说了。

我公司的项目里用了 Apache Calcite 作为融合数据的计算引擎,解决不同存储格式的数据统一计算就是一个很好的应用。
hantsy
2020-12-15 13:36:22 +08:00
@wangyanrui 我了解国内的即使用 JPA 的,很多也是先设计了数据库,用逆向工具(比如 PowerDesigner,Hibernate Tools )反向生成一些 Entity,那么 Entity 类和表几乎 100 % 对应。

首先逆向工具都是针对 Legacy 程序设计的,对于新项目使用,生成的代码,我真的觉得很恶心。

良好的 OOP 设计情况下,JPA 只有 Entity 与表(或者视图)对应,JPA 还有其它形式的模型,比如 Embeddable,Entity 中使用 ElementCollection 等。最终能够完全匹配不多。
hantsy
2020-12-15 13:41:49 +08:00
@Braisdom AWS 是数据库也有用混合引擎,现在好像很多这样的数据库例子。NOSQL 产品太多了,目前还是 Redis,Mongo,Noe4j 几个不同领域的具有代表性。

Noe4j 之前还兼容 JDBC 的接口,现在 4 。0 以后好像不支持,不过 Neo4j 的 Cypher 查询语言真的强大。
Braisdom
2020-12-15 13:47:33 +08:00
@hantsy 是的,我是做传统线下零售数据系统的,不同类型的数据或不同访问频率的数据用不同的存储方式是很正常的,Cypher 这个我还真得仔细研究一下,Redis 和 Mongo 我都用了,Noe4j 没玩过,值得借鉴
gowk
2020-12-15 14:00:23 +08:00
那个 orm 男人,他来了
Braisdom
2020-12-15 14:02:41 +08:00
@gowk 你这个 tag 我很喜欢... 过段时间我准备换一个,哈哈
WhoMercy
2020-12-15 14:22:17 +08:00
感谢分享经验感悟,这样的推广很不错,👍
brezp
2020-12-15 14:54:43 +08:00
楼上说楼主推广自己的东西的, 别人楼主也好歹是带着自己的东西来交流吧, 你反感不点进来不就完事了么?
cloudhuang
2020-12-15 15:47:58 +08:00
能讨论总是有意的,不过看了楼主提的例子,有点“为赋新词强说愁”的感觉:

> 语义表达的双重性
"一个 Column 可以进行排序、算术运算、比较运算等",这个在 SQL 层面也并非是有 column 自身提供的语义,如果是,那么也就没有 order by, group by......什么事情了。

> 语法一致性
我不是太理解,两个完全不等同的东西,讲什么一致性?

> 也无法 Java 对语义的解析和执行过程进行干预,也就导致了 Java 的表达式无法直接转换为 SQL 表达式,只能以字符串的形式进行拼接
如果和数据库的交互形式,最终都是 SQL,那么不同的框架,只是拼接的形式不同而已,比如 Hibernate,比如 MyBastis

> Java 运算符重载
不知道楼主说的是什么意思,Java 应该是没有运算符重载一说的(C++的运算符重载)
Braisdom
2020-12-15 16:17:07 +08:00
@cloudhuang 当然不是,我再补充一下(后续有必要写一份文档,详细说明):
1 )语义的双重性:其实就是程序的开发中,同一个编程元素要表达两个不同的含义,例如:一个 Class 中的 Field 在 Java 中是一种类型的数据或状态的载体,例如:class User 中 private String name,从语义上讲,它只能保存 User 实例中的 name 的状态,如果将 User 的实例用于拼接 SQL,这个 name 其实是对应的 users 表中的一个 column, 这种语义的表达,在目前的编程模型中是无法做的,因为 SQL 域中,name 是另一种类型 Column, Column 也有自身的状态和行为,例如:user.name.asc(), user.name.orderBy() 等。这就需要两种不同的定义方式,User, UserDO 两种不同的定义方式表达同一个模型定义, 这也就导致了重复编码和静态生成的变更问题。

2) 至于 Java 的运算符重载,你可以参考: https://www.v2ex.com/t/734572#reply103
里面有详细的描述和讨论。
zhangbohun
2020-12-15 16:21:20 +08:00
想看 sql,json,orm 三巨头一起互打广告
Braisdom
2020-12-15 16:34:14 +08:00
@cloudhuang 更直白一点的说,
class User {
private String name;
}

class UserDO {
private Column name;
}

Java 域中,name 只能用来存储状态,类型为 String
SQL 域中,name 是另一个类型 Column, Column 中有状态和行为

传统的方法就是静态生成另一个类 UserDO, 而 ObjectiveSQL 中则不需要,是动态生成。
Braisdom
2020-12-15 16:36:54 +08:00
@zhangbohun 有道理,自己的项目希望更多人知道,开源的肯定不太会花费用去打广告,我也只能用自己的知识去交换眼球,希望能够理解。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/735605

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX