zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Object类的方法简记
    run()和start()调用问题简记
    面向对象设计
    关于JVM的简记
    操作运算符的简记
    jdbc简记
    synchronized的简记
    垃圾回收的一些简记
    java.io.IOException: Stream closed
    Java-文件名、目录名或卷标语法不正确
  • 原文地址:https://www.cnblogs.com/ScarecrowAnBird/p/14052309.html
Copyright © 2011-2022 走看看