最近详细了解了一下ORM,这里记录一下。
当下我们使用的ORM("对象-关系 映射"(Object Relational Mapping))框架中,JPA/Hibernate/Mybatis占了半边天,它们都有各自的优势和使用场景。
最近发现了一个之前从来没用的ORM框架jOOQ,非常有意思,为数据处理提供了一种全新的方式
面向对象编程和关系型数据库,都是目前最流行的技术,但是它们的模型是不一样的。
面向对象编程把所有实体看成对象(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,操作数据库的写法如下。
res = db.execSql(sql);
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。
许多语言都有自己的 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
字段。
查看我的博客:
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。我最终得到更清晰和可理解的代码。
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的方式如下:
create.select(BOOK.TITLE)
.from(BOOK)
.where(BOOK.PUBLISHED_IN.eq(2011))
.orderBy(BOOK.TITLE)
从mvnrepository上查询jOOQ,发现它的第一个版本早在2011年,到现在已经有9个年头了,社区依然活跃。
jOOQ之所以诞生,大概是人们厌倦了直接写SQL,用java以流式的方式写SQL,上手成本并不算高,熟练以后应该很舒服。
jOOQ是将SQL语言集成到Java中的一种简单方法,它使开发人员可以直接用Java快速,安全地编写高质量的SQL,从而使他们可以专注于自己的业务。
绝大部分数据库函数,都转化为了java方法,使用起来自然方便,它还能进行必要的类型检查,规避了大多数语法错误。
它有下面这几个优势:
java
/** 一个复杂的查询
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(*)
FROM AUTHOR
JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
WHERE BOOK.LANGUAGE = 'DE'
AND BOOK.PUBLISHED > DATE '2008-01-01'
GROUP BY AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
HAVING COUNT(*) > 5
ORDER BY AUTHOR.LAST_NAME ASC NULLS FIRST
LIMIT 2
OFFSET 1
**/
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())
.from(AUTHOR)
.join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID))
.where(BOOK.LANGUAGE.eq("DE"))
.and(BOOK.PUBLISHED.gt(date("2008-01-01")))
.groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
.having(count().gt(5))
.orderBy(AUTHOR.LAST_NAME.asc().nullsFirst())
.limit(2)
.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: ---------> ^^^^
这里简单介绍了JOOQ以及为什么要使用它,作为一个强力的ORM框架,其从一个新的方向尝试更快更好的编写SQL,很值得我们学习。
参考项目:jOOQ-spring-boot-example,
以前项目用过JPA,后面为了控制SQL使用MyBatis(强大组件,包含缓存事务等处理),等以后项目再试试JOOQ吧。
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