当下我们使用的ORM框架中,Hibernate/Mybatis占了半边天,它们都有各自的优势和使用场景。
最近发现了一个之前从来没用的ORM框架jOOQ,非常有意思,为数据处理提供了一种全新的方式。
1. jOOQ是什么
JOOQ(Java Object Oriented Query)是一个开源框架,它可以把数据库模型的基本信息,比如表名,字段名自动生成相应的Java类;并在此基础上提供了一整套数据处理的API。
Hibernate致力于以面向对象的方式处理数据,隐藏了所有SQL相关处理;Mybatis则是在XML文件中写SQL。
jOOQ与它们都不同,它致力于通过java语言以最简单的形式写SQL。使用jOOQ DSL(Domain-Specific Language), SQL看起来几乎是由Java本地支持的。
原生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,上手成本并不算高,熟练以后应该很舒服。
2. jOOQ解决了什么问题
jOOQ是将SQL语言集成到Java中的一种简单方法,它使开发人员可以直接用Java快速,安全地编写高质量的SQL,从而使他们可以专注于自己的业务。
绝大部分数据库函数,都转化为了java方法,使用起来自然方便,它还能进行必要的类型检查,规避了大多数语法错误。
它有下面这几个优势:
- 数据库优先,它不提倡隐藏SQL;与Mybatis一样,以SQL优先,同时可以快速安全的编写SQL。
- 类型安全的SQL,它支持列类型检查、行值表达式检查、SQL语法检查。
- 代码自动生成,自动生成一份Model类,不需要再手动维护它们。
- SQL标准化,各个数据库方言存在很多细微差别,jOOQ可以自动进行转换
- 支持区分不同环境,可以动态切换开发数据库、测试数据库等不同环境的数据库
- 查询生命周期,jOOQ不尝试隐藏SQL,围绕整个生命周期开放了接口,我们可以做日志自定义,事件触发,SQL转换等处理。
- 支持编写存储过程
3. 更多的例子
/** 一个复杂的查询
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: ---------> ^^^^
4. 小结
本文简单介绍了JOOQ以及为什么要使用它,作为一个强力的ORM框架,其从一个新的方向尝试更快更好的编写SQL,很值得我们学习。
本文并没有一步一步的写出可运行的示例,因为这个过程本身很简单,没有必要占篇幅。
当然各位也可以参考这个项目jOOQ-spring-boot-example,它是从官方示例中剥离出来的,导入IDEA后可以直接运行。