ORM有一个简单的,可立即投入生产的解决方案,在Java世界中是显而易见的。 让我们在这篇文章中进行研究,并结合以下主题:
- ORM / Hibernate在2014年–大街上的单词
- ORM 仍然是计算机科学的越南
- ORM只有2个主要目标
- ORM什么时候有意义?
- ORM问题的简单解决方案
- 生产就绪的基于Java的ORM Java替代品
ORM / Hibernate在2014年–大街上的单词
自从ORM出现以来已经快20年了,很快我们将到达事实上的创建以及Java世界中可能最好的ORM实现:Hibernate的15岁生日。
然后,我们期望这是一个众所周知的问题。 但是,这些天开发人员对Hibernate和ORM的看法是什么?
让我们从有关该主题的两个最新帖子中引用一些内容: 关于Hibernate和JPA Hibernate Alternatives的 想法 :
存在与使用休眠有关的性能问题。
许多业务操作和报告涉及编写复杂的查询。 根据对象编写它们并进行维护似乎很困难。
我们不需要一本900页的书来学习一个新的框架。
作为Java开发人员,我们可以很容易地与之联系:ORM框架往往会给出错误的错误消息,很难做到映射,并且在首次遇到运行时行为(即带有惰性初始化异常)可能会令人惊讶。
谁不必维护使用Open Session In View模式的应用程序,该应用程序会生成大量需要数周时间进行优化的SQL请求?
我相信从字面上看要真正理解Hibernate可能要花费几年时间,需要大量的实践知识以及对Java Persistence with Hibernate的阅读(在即将发行的第二版中还有600页)。
是否对Hibernate提出批评?
我个人并不这么认为,实际上,大多数开发人员确实批评了对象关系映射方法本身的复杂性,而不是使用给定语言对它进行具体的ORM实现。
这种情绪似乎是周期性的来回波动的,也许是新一代的开发人员进入劳动力市场时。 在经过数小时和数天的尝试后,要做的事情应该简单得多,这只是一种自然的感觉。
事实是,这里存在一个问题:为什么许多项目到现在仍然花费30%的时间来开发持久层?
ORM是计算机科学的越南
问题是ORM问题很复杂,没有好的解决方案。 任何解决方案都是一个巨大的妥协。
在大约10年前,在Stackoverflow的创建者之一杰夫·阿特伍德 ( Jeff Atwood)的博客中 ,ORM已被著名地命名为越南计算机科学。
ORM的问题是众所周知的,在这里我们将不进行详细介绍,这是Martin Fowler 总结的 ORM为何困难的原因:
- 对象身份与数据库身份
- 如何在关系世界中映射面向对象的继承
- 数据库中的单向关联与OO世界中的双向关联
- 数据导航–延迟加载,渴望获取
- 数据库事务与面向对象世界中没有回滚
这仅是主要障碍。 问题还在于,很容易忘记我们最初想要达到的目标。
ORM只有2个主要目标
ORM有两个明确定义的主要目标:
- 将来自OO世界的对象映射到关系数据库中的表中
- 提供一种运行时机制,以使对象的内存中图和一组数据库表保持同步
鉴于此,我们一般应该何时使用Hibernate和ORM?
ORM什么时候有意义?
当使用域驱动开发方法完成手头的项目时,ORM是有意义的,其中整个程序是围绕一组称为域模型的核心类构建的,这些类代表了现实世界中的概念,例如Customer
, Invoice
等。
如果项目没有需要DDD的最低阈值复杂度,那么ORM可能会显得过大。 问题在于,即使最简单的企业应用程序也远远超过此阈值,因此ORM确实在大多数情况下会减轻其负担。
仅仅是ORM很难学习并且充满陷阱。 那么我们如何解决这个问题呢?
ORM问题的简单解决方案
曾经有人说过这样的话:
聪明的人可以解决问题,而聪明的人可以避免。
正如编程中经常发生的那样,我们可以从头开始找到解决方案,然后看看我们要解决的问题:
因此,我们正在尝试将对象的内存中图与一组表进行同步。 但是,这是两种完全不同的数据结构类型!
但是,哪种数据结构最通用? 事实证明,图是两者中最通用的一个:实际上,一组链接的数据库表实际上只是图的一种特殊类型。
几乎所有其他数据结构都可以说相同。
图及其遍历非常容易理解,并且具有数十年的可用知识体系,类似于建立关系数据库所基于的理论:关系代数。
解决阻抗失配
逻辑结论是,消除ORM阻抗不匹配的解决方案是为了消除不匹配本身:
让我们将内存中的域对象图存储在具有事务功能的图数据库中!
通过首先消除对映射的需求,从而解决了映射问题。
生产就绪的ORM问题解决方案
说起来容易做起来难,不是吗? 事实证明,图形数据库已经存在多年了,Java社区中的主要示例是Neo4j 。
Neo4j是稳定且成熟的产品,已得到很好的理解和记录,请参阅《 Neo4J在行动》一书。 它可以用作外部服务器,也可以在Java进程本身内部以嵌入式模式使用。
但是它的核心API完全是关于图和节点的,就像这样:
GraphDatabaseService gds = new EmbeddedGraphDatabase("/path/to/store");
Node forrest=gds.createNode();
forrest.setProperty("title","Forrest Gump");
forrest.setProperty("year",1994);
gds.index().forNodes("movies").add(forrest,"id",1);
Node tom=gds.createNode();
问题在于,这与域驱动的开发相距太远,编写此内容就像手动编写JDBC。
这是像Hibernate这样的框架的典型任务,最大的区别在于,因为阻抗失配很小,所以这种框架可以以更透明和更少侵入的方式运行。
事实证明,这样的框架已经编写。
对Neo4J的Spring支持
Spring框架的创建者之一Rod Rod Johnson承担了为自己实现Neo4j集成的初始版本Spring Data Neo4j项目的任务。
这是Rod Johnson在有关框架设计的文档中的前言的重要摘录:
它使用AspectJ从您的域模型中删除持久性代码确实是创新的,并且是当今Java技术的最前沿。
因此,Spring Data Neo4J是一个基于AOP的框架,它以相对透明的方式包装域对象,并将对象的内存中图与Neo4j事务性数据存储同步。
旨在以简化的方式编写应用程序的持久层,类似于Spring Data JPA。
到图形数据库的映射看起来如何
事实证明,所需的映射有限( 教程 )。 我们需要一个标记我们要使其持久化的类,并定义一个将用作ID的字段:
@NodeEntity
class Movie {
@GraphId Long nodeId;
String id;
String title;
int year;
Set cast;
}
还有其他注释(每个文档增加5个注释),例如,用于定义索引以及与属性的关系等。与Hibernate相比,同一域模型的注释中只有一小部分。
查询语言是什么样的?
推荐的查询语言是Cypher ,这是一种基于ASCII艺术的语言。 查询可以看起来像这样:
// returns users who rated a movie based on movie title (movieTitle parameter) higher than rating (rating parameter)
@Query("start movie=node:Movie(title={0}) " +
"match (movie)<-[r:RATED]-(user) " +
"where r.stars > {1} " +
"return user")
Iterable getUsersWhoRatedMovieFromTitle(String movieTitle, Integer rating);
这是一种称为Cypher的查询语言,它基于ASCII艺术。 查询语言与JPQL或SQL有很大不同,并且暗示学习曲线。
仍然在学习曲线之后,该语言仍允许编写性能查询,这通常在关系数据库中会出现问题。
图与关系数据库中查询的性能
让我们比较一些常见的查询类型,以及它们在图形数据库和关系数据库中应如何执行:
- 通过ID查找:例如,通过对索引树进行二进制搜索,找到匹配项并在结果后添加“指针”来实现。 这是一个(非常)简化的描述,但是对于两个数据库来说可能都是相同的。 没有什么明显的原因可以解释为什么在图形数据库中这种查询要比在关系数据库中花费更多的时间。
- 查找父关系:这是关系数据库难以解决的查询类型。 自联接可能导致大型表的笛卡尔积,从而使数据库停止运行。 图数据库可以执行这些查询的一小部分。
- 通过非索引列查找:由于表的物理结构,关系数据库可以更快地扫描表,并且事实是一次读取通常不会带来多行。 但是无论如何,在关系数据库中都应避免这种类型的查询(表扫描)。
这里还有更多要说的,但是没有迹象表明(基于ready-可用的与DDD相关的公共基准),由于查询性能,基于图形的数据存储不适合进行DDD。
结论
我个人找不到任何(概念上的)原因,为什么具有事务功能的图形数据库不能理想地适合进行域驱动开发,而不是关系数据库和ORM的替代方法。
没有任何一种数据存储能够完美地适合每个用例,但是我们可以问一个问题:图数据库是否不应该成为DDD的默认数据库,并关系到异常。
ORM的消失将意味着大大减少实施项目的复杂性和时间。
DDD在企业中的未来
消除阻抗不匹配和某些查询类型的性能提高可能是推动采用基于图的DDD解决方案的杀手级功能。
我们可以看到实际的障碍:操作更喜欢关系数据库,供应商合同锁定,必须学习新的查询语言,劳动力市场的专业知识有限等。
但是经济优势在那里,技术也在那里。 如果是这种情况,通常只是时间问题。
那您呢,您能想到基于图的DDD无法工作的任何原因吗? 请随时关注下面的评论。
翻译自: https://www.javacodegeeks.com/2014/09/solving-orm-keep-the-o-drop-the-r-no-need-for-the-m.html