zoukankan      html  css  js  c++  java
  • Spring Data JPA 与 MyBatis 的一些心得

    Spring Data JPA 与 MyBatis 的一些心得

    引言

    之前一直使用 MyBatis ,习惯了自己写增删改查的 SQL 。在入职新公司后,公司是用的是 Spring Data JPA ,半年过去了,由于公司本身是互联网行业,开发和迭代快速,比较深刻的体会到了 Spring Data JPA 和 MyBatis 的优缺点。
    先下结语,互联网行业,开发和迭代快速,如果没有 Spring Data JPA / Hibernate 的大牛,或者技术文档没有维护的想法,不建议使用 Spring Data JPA ,哪怕 Spring Data JPA 具有初始的开发速度优势。

    Spring Data JPA 与 MyBatis

    由于 Spring Data JPA 默认使用 Hibernate 作为 ORM 实现,Spring Data JPA 与 MyBatis 对比,其实也就是 Hibernate 与 MyBatis 的对比。

    1. Spring Data JPA 与 MyBatis 的查询构建

      Spring Data JPA 中,如果一个 DAO 查询类继承了 JpaRepository,即

      public interface classADAO extends JpaRepository<classA,Integer>{
      }
      

      那么查询所有的 classA 有多简单呢:List<classA> list =classADAO.findAll();

      核心在于什么, Spring Data JPA (Hibernate) 是面向对象的,MyBatis 是面向关系的。

      但面向对象麻烦的地方也就在这里,如果有级联呢?

      它把表看做一个对象,那表A是一个对象 classA 。如果表A通过中间表B关联了表C,那么毫无意义的表B也成了一个对象。注意,这些都是要写入类中的。

      public class ClassA implements Serializable {
      
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          Integer id;
          
          @OneToMany(mappedBy = "classA", cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
          private List<classB> listB;
      }
      
      public class ClassB implements Serializable {
      
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          Integer id;
          
          @OneToMany(mappedBy = "classB", cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
          private List<classC> listC;
      }
      

      仔细想想,从 classA 到 classC 查询实现会比较复杂。

      所以要用好 Spring Data JPA 的查询,一定要有一位大牛,对数据库设计时的表关系进行取舍,尽可能的避免上文这种情况出现。当然肯定还有其他需要考虑的地方,我这方面经验尚缺。

      但是用好了,就可以很方便的查询,不用 SQL 写来写去,对吧,而 MyBatis 的 SQL 是绕不开的。

    2. Spring Data JPA 与 MyBatis 的文档维护

      由上一点就可以延伸到这一点,我之前提到过, Spring Data JPA 具有初始的开发速度优势。

      为什么,这里可能有些疑问,因为就算你简单的 SQL 能避免,但是总有多表条件查询啊。是的,Spring Data JPA 还有一样利器 Specification ,我贴下基本的结构,你就明白了

      public interface ClassASpec {
      	static Specification<ClassA> spec(ClassAQuery classAQuery, Boolean checkUnique) {
      		return (root, query, cb) -> {
      			List<Predicate> predicates = new ArrayList<>();
      			if (classAQuery.getId() != null) {
      				if (checkUnique != null && checkUnique) {
      					predicates.add(cb.notEqual(root.get("id"), classAQuery.getId()));
      				} else {
      					predicates.add(cb.equal(root.get("id"), classAQuery.getId()));
      				}
      			}
      			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
      		};
      	}
      
      }
      

      明白了吧,这就是不用写 SQL 的原因所在,所有的查询以此种方式从对象映射为关系,自动生成 SQL。

      那问题来了,Spring Data JPA 的优势在这里处理不好就会变成劣势。

      处于互联网行业,开发是快速的,迭代是快速的,数据库中的表关系会层层叠加,表字段会层层叠加,如果不注意维护文档,一段时间,你可以想象得到,这个查询类 Specification 会变成何种怪物。

      有朋友就问了,我不能通过看 SQL 来看懂查询逻辑吗。可以,极费时间,你可以通过日志查看自动生成的 SQL ,但一是由于级联的存在,二是由于 Specification 自动生成的 SQL 会加载每个表及每个表的所有字段,且会给每个字段生成别名,相信我,你看到 SQL 会爆炸的。

      我拿一个实际中常见的多表联合条件查询 SQL 举例(来源于网络):

      SELECT
      	CATENTRY.PARTNUMBER,
      	CATENTRY.CATENTRY_ID,
      	CATENTDESC.NAME,
      	MASSOCCECE.MASSOCCECE_ID 
      FROM
      	CATENTDESC,
      	CATENTRY,
      	CATGROUP,
      	CATGRPREL,
      	CATGPENREL,
      	MASSOCCECE 
      WHERE
      	CATENTDESC.LANGUAGE_ID = 44 
      	AND CATENTRY.MARKFORDELETE = 0 
      	AND CATENTDESC.CATENTRY_ID = CATENTRY.CATENTRY_ID 
      	AND CATENTRY.CATENTRY_ID = MASSOCCECE.CATENTRY_ID_TO 
      	AND MASSOCCECE.CATENTRY_ID_FROM = 299811 
      	-- AND CATGPENREL.CATALOG_ID = 10201 
      	AND MASSOCCECE.MASSOCTYPE_ID = 'EDITORIAL' 
      	AND CATGPENREL.CATENTRY_ID = MASSOCCECE.CATENTRY_ID_TO 
      	AND CATGRPREL.CATGROUP_ID_CHILD = CATGPENREL.CATGROUP_ID 
      	AND CATGRPREL.CATGROUP_ID_PARENT = CATGROUP.CATGROUP_ID 
      	AND CATGRPREL.CATALOG_ID = CATGPENREL.CATALOG_ID 
      	AND CATGROUP.FIELD1 = 'EDITORIAL' 
      GROUP BY
      	CATENTRY.PARTNUMBER,
      	CATENTRY.CATENTRY_ID,
      	CATENTDESC.NAME,
      	MASSOCCECE.MASSOCCECE_ID 
      ORDER BY
      	MASSOCCECE.MASSOCCECE_ID WITH UR
      

      如果没有文档,MyBatis 的语句好歹是直观的。哪怕没文档、排版乱,格式化后,是看得懂的。升级直接改 SQL ,还可以拜托 DBA 优化。

      要是用 Spring Data JPA 做的话,查询类会极度复杂。没有文档,开发人员一换,后边的开发人员头都得想破。谈到升级和优化,DBA 无从下手,必须有个 Spring Data JPA / Hibernate 的大牛。

    结语

    1. 在简单数据库逻辑查询(单表)下 Mybatis 开发效率会比 Spring Data JPA 低,但不会低多少
    2. 在复杂数据库逻辑查询(多表、联合)下,随着表关系和表字段的迭代, Spring Data JPA 查询的效率和优化比 Mybatis 困难得多

    所以,互联网行业,因为开发和迭代快速,如果没有 Spring Data JPA / Hibernate 的大牛,或者技术文档没有维护的想法,不建议使用 Spring Data JPA ,哪怕 Spring Data JPA 具有初始的开发速度优势。

  • 相关阅读:
    display: flex
    TTStand --Variant的应用
    跨域
    HTTP 响应状态代码
    SQL Server 2017 Developer and Express
    WPF 中 通过点击ListBox中的元素自动选中一整项
    C#计算屏幕的物理宽和高
    C#常用设计模式
    EntityFrameworkCore之工作单元的封装
    内存包装类 Memory 和 Span 相关类型
  • 原文地址:https://www.cnblogs.com/Sherlock-J/p/12925926.html
Copyright © 2011-2022 走看看