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 具有初始的开发速度优势。

posted @ 2019-10-28 18:49  夏洛克卷  阅读(200)  评论(0编辑  收藏  举报