ORM优缺点详解,已经JOOQ、MyBatis介绍

转自:https://blog.csdn.net/zzhongcy/article/details/105293602?utm_medium=distribute.pc_relevant.none-task-blog-title-10&spm=1001.2101.3001.4242

最近详细了解了一下ORM,这里记录一下。

图片描述

当下我们使用的ORM("对象-关系 映射"(Object Relational Mapping))框架中,JPA/Hibernate/Mybatis占了半边天,它们都有各自的优势和使用场景。

最近发现了一个之前从来没用的ORM框架jOOQ,非常有意思,为数据处理提供了一种全新的方式

一、ORM 

1.1、ORM概述

面向对象编程和关系型数据库,都是目前最流行的技术,但是它们的模型是不一样的。

面向对象编程把所有实体看成对象(object),关系型数据库则是采用实体之间的关系(relation)连接数据。很早就有人提出,关系也可以用对象表达,这样的话,就能使用面向对象编程,来操作关系型数据库。

简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。

ORM 把数据库映射成对象。

  • 数据库的表(table) --> 类(class)
  • 记录(record,行数据)--> 对象(object)
  • 字段(field)--> 对象的属性(attribute)

举例来说,下面是一行 SQL 语句。

SELECT id, first_name, last_name, phone, birth_date, sex
 FROM persons 
 WHERE id = 10

程序直接运行 SQL,操作数据库的写法如下。

1 res = db.execSql(sql);
2 name = res[0]["FIRST_NAME"];

改成 ORM 的写法如下。

p = Person.get(10);
name = p.first_name;
 

一比较就可以发现,ORM 使用对象,封装了数据库操作,因此可以不碰 SQL 语言。开发者只使用面向对象编程,与数据对象直接交互,不用关心底层数据库。

总结起来,ORM 有下面这些优点。

  • 数据模型都在一个地方定义,更容易更新和维护,也利于重用代码。
  • ORM 有现成的工具,很多功能都可以自动完成,比如数据消毒、预处理、事务等等。
  • 它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰。
  • 基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解。
  • 你不必编写性能不佳的 SQL。

但是,ORM 也有很突出的缺点。

  • ORM 库不是轻量级工具,需要花很多精力学习和设置。
  • 对于复杂的查询,ORM 要么是无法表达,要么是性能不如原生的 SQL。
  • ORM 抽象掉了数据库层,开发者无法了解底层的数据库操作,也无法定制一些特殊的 SQL。

1.2、命名规定

许多语言都有自己的 ORM 库,最典型、最规范的实现公认是 Ruby 语言的 Active Record。Active Record 对于对象和数据库表的映射,有一些命名限制。

(1)一个类对应一张表。类名是单数,且首字母大写;表名是复数,且全部是小写。比如,表books对应类Book

(2)如果名字是不规则复数,则类名依照英语习惯命名,比如,表mice对应类Mouse,表people对应类Person

(3)如果名字包含多个单词,那么类名使用首字母全部大写的骆驼拼写法,而表名使用下划线分隔的小写单词。比如,表book_clubs对应类BookClub,表line_items对应类LineItem

(4)每个表都必须有一个主键字段,通常是叫做id的整数字段。外键字段名约定为单数的表名 + 下划线 + id,比如item_id表示该字段对应items表的id字段。

二、MyBatis

查看我的博客:

https://blog.csdn.net/yangyangye/category_9227808.html

最大的体会是:MyBatis能让我控制SQL

      对于任何使用关系数据库的严重项目,您无法逃避学习SQL。大多数ORM试图通过提供更高级别的抽象来使您与SQL隔离。但是作为交换,他们强迫你学习一个新的API或一个抽象的查询语言。这些API /查询语言无论如何都会生成SQL,所以唯一的区别是你不知道它们是什么,直到你打开引擎盖。在很多情况下,我可以用单个语句编写的查询将以两个或更多语句生成,从而降低性能。

      现在我突然回到ORM并调整它以产生更高效的查询。有时候,API不够丰富,无法满足所需要的任何事情,无论如何,我都必须逃避SQL语言。为什么要这么麻烦?如果我必须知道SQL,为什么不直接自己写,直接优化呢?教学框架将结果映射到对象中要容易得多。

      猜猜看,这正是MyBatis所做的 - 在这里看到结果图。它教MyBatis如何将查询结果映射到一个Transaction对象,并引用一个Account和一个Category。我最终得到更清晰和可理解的代码。

所以:我希望你能明白为什么我喜欢MyBatis。这将是我未来Java的默认ORM

三、JOOQ

3.1 介绍

JOOQ(Java Object Oriented Query)是一个开源框架,它可以把数据库模型的基本信息,比如表名,字段名自动生成相应的Java类;并在此基础上提供了一整套数据处理的API。

jOOQ(Java Object Oriented Querying,即面向Java对象查询)是一个高效地合并了复杂SQL、类型安全、源码生成、ActiveRecord、存储过程以及高级数据类型的Java API的类库。 

Hibernate致力于以面向对象的方式处理数据,隐藏了所有SQL相关处理;

Mybatis则是在XML文件中写SQL。

jOOQ与它们都不同,它致力于通过java语言以最简单的形式写SQL。使用jOOQ DSL(Domain-Specific Language), SQL看起来几乎是由Java本地支持的。

      对于写Java的码农来说ORMS再也熟悉不过了,不管是Hibernate或者Mybatis,都能简单的使用实体映射来访问数据库。但有时候这些 ‘智能’的对象关系映射又显得笨拙,没有直接使用原生sql来的灵活和简单,而且对于一些如:joins,union, nested selects等复杂的操作支持的不友好。JOOQ 既吸取了传统ORM操作数据的简单性和安全性,又保留了原生sql的灵活性,它更像是介于 ORMS和JDBC的中间层。对于喜欢写sql的码农来说,JOOQ可以完全满足你控制欲,可以是用Java代码写出sql的感觉来。就像官网说的那样 :

get back in control of your sql

 
原生SQL如下:
SELECT TITLE
 
FROM BOOK
 
WHERE BOOK.PUBLISHED_IN = 2011
 
ORDER BY BOOK.TITLE
使用jOOQ写SQL的方式如下:
1 create.select(BOOK.TITLE)
2 
3 .from(BOOK)
4 
5 
6 .where(BOOK.PUBLISHED_IN.eq(2011))
7 
8 
9 .orderBy(BOOK.TITLE)

 

从mvnrepository上查询jOOQ,发现它的第一个版本早在2011年,到现在已经有9个年头了,社区依然活跃。
jOOQ之所以诞生,大概是人们厌倦了直接写SQL,用java以流式的方式写SQL,上手成本并不算高,熟练以后应该很舒服。

3.2. jOOQ解决了什么问题

jOOQ是将SQL语言集成到Java中的一种简单方法,它使开发人员可以直接用Java快速,安全地编写高质量的SQL,从而使他们可以专注于自己的业务。

绝大部分数据库函数,都转化为了java方法,使用起来自然方便,它还能进行必要的类型检查,规避了大多数语法错误。

它有下面这几个优势:

  • 数据库优先,它不提倡隐藏SQL;与Mybatis一样,以SQL优先,同时可以快速安全的编写SQL。
  • DSL(Domain Specific Language )风格,代码够简单和清晰。遇到不会写的sql可以充分利用IDEA代码提示功能轻松完成。
  • 类型安全的SQL,它支持列类型检查、行值表达式检查、SQL语法检查。保留了传统ORM 的优点,简单操作性,安全性,类型安全等。不需要复杂的配置,并且可以利用Java 8 Stream API 做更加复杂的数据转换。
  • 代码自动生成,自动生成一份Model类,不需要再手动维护它们。
  • SQL标准化,各个数据库方言存在很多细微差别,jOOQ可以自动进行转换
  • 支持区分不同环境,可以动态切换开发数据库、测试数据库等不同环境的数据库
  • 查询生命周期,jOOQ不尝试隐藏SQL,围绕整个生命周期开放了接口,我们可以做日志自定义,事件触发,SQL转换等处理。
  • 支持编写存储过程
  •  
  • 支持主流的RDMS和更多的特性,如self-joins,union,存储过程,复杂的子查询等等。
  • 丰富的Fluent API和完善文档。
  • runtime schema mapping 可以支持多个数据库schema访问。简单来说使用一个连接池可以访问N个DB schema,使用比较多的就是SaaS应用的多租户场景。

3.3. 更多的例子

java

 1 2 
 3  
 4  
 5 
 6 SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(*)
 7 
 8 FROM AUTHOR
 9 
10 JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
11 
12 
13 WHERE BOOK.LANGUAGE = 'DE'
14 
15 
16 AND BOOK.PUBLISHED > DATE '2008-01-01'
17 
18 
19 GROUP BY AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
20 
21 
22 HAVING COUNT(*) > 5
23 
24 
25 ORDER BY AUTHOR.LAST_NAME ASC NULLS FIRST
26 
27 
28 LIMIT 2
29 
30 
31 OFFSET 1
32 
33 
34 

c

 1 reate.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())
 2 
 3 .from(AUTHOR)
 4 
 5 .join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID))
 6 
 7 .where(BOOK.LANGUAGE.eq("DE"))
 8 
 9 .and(BOOK.PUBLISHED.gt(date("2008-01-01")))
10 
11 .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
12 
13 .having(count().gt(5))
14 
15 .orderBy(AUTHOR.LAST_NAME.asc().nullsFirst())
16 
17 .limit(2)
18 
19 .offset(1)

//类型检查

select().from(t).where(t.a.eq(select(t2.x).from(t2));

// Type-check here: ---------------> ^^^^

select().from(t).where(t.a.eq(any(select(t2.x).from(t2)));

// Type-check here: -------------------> ^^^^

select().from(t).where(t.a.in(select(t2.x).from(t2));

// Type-check here: ---------------> ^^^^

//表达式类型检查

select().from(t).where(row(t.a, t.b).eq(1, 2));

// Type-check here: -----------------> ^^^^

select().from(t).where(row(t.a, t.b).overlaps(date1, date2));

// Type-check here: ------------------------> ^^^^^^^^^^^^

select().from(t).where(row(t.a, t.b).in(select(t2.x, t2.y)));

// Type-check here: -------------------------> ^^^^^^^^^^

update(t).set(row(t.a, t.b), select(t2.x, t2.y).where(...));

// Type-check here: --------------> ^^^^^^^^^^

insertInto(t, t.a, t.b).values(1, 2);

// Type-check here: ---------> ^^^^

 

  1. 这里简单介绍了JOOQ以及为什么要使用它,作为一个强力的ORM框架,其从一个新的方向尝试更快更好的编写SQL,很值得我们学习。

参考项目:jOOQ-spring-boot-example

4、总结

    以前项目用过JPA,后面为了控制SQL使用MyBatis(强大组件,包含缓存事务等处理),等以后项目再试试JOOQ吧。

5、参考:

http://www.ruanyifeng.com/blog/2019/02/orm-tutorial.html

https://segmentfault.com/a/1190000006748584?utm_source=tuicool&utm_medium=referral

https://segmentfault.com/a/1190000020490982

http://bbs.learnfuture.com/topic/3937

https://www.jianshu.com/p/4f3cb36f10fe

原文地址:https://www.cnblogs.com/ScarecrowAnBird/p/14052309.html