小工具知识网

当前位置: 首页 > 行业知识 > Spring Data JPA 与 MyBatisPlus的比较

行业知识

Spring Data JPA 与 MyBatisPlus的比较

2026-11-03 09:12:57 来源:互联网转载

1 前言

JPA(Java Persistence API)和MyBatis Plus是两种不同的持久化框架,它们具有不同的特点和适用场景。

JPA是Java官方的持久化规范,它提供了一种基于对象的编程模型,可以通过注解或XML配置来实现对象与数据库的映射关系。JPA的优点是可以对数据库进行更高级的操作,如查询、更新、删除等,同时也支持事务管理和缓存机制,能够更好地支持复杂的业务逻辑。

MyBatis Plus (MPP) 是在MyBatis基础上进行封装的增强版本,它提供了更简单易用的API和更高效的性能。MyBatis Plus通过XML或注解的方式来配置数据库映射关系,并提供了丰富的查询、更新、删除操作的方法。相对于JPA,MyBatis Plus配置简单、易于上手,同时也灵活性较高,能够更好地满足项目的特定需求。

如果只是针对单表的增删改查,两者十分相似,本质上都算ORM框架,那么到底什么时候适合用JPA,什么时候用MyBatisPlus,下面做下这两者的详细对比。

2 POM依赖

  • JPA
        org.springframework.boot    spring-boot-starter-data-jpa
    • MPP
          com.baomidou    mybatis-plus-boot-starter

      3 Entity定义

      • JPA
        import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import javax.persistence.GeneratedValue;@Entity@Table(name = "dept")public class Dept {@Id@Column(name = "id")@GeneratedValue(strategy = GenerationType.AUTO)private Long id;@Column(name = "code")private String code;@Column(name = "name")private String name;}
        • MPP
          import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableId;@TableName(value = "dept")public class Dept {    @TableId(value = "id", type = IdType.AUTO)    private Long id;    @TableField(value = "code")    private String code;    @TableField(value = "name")    private String name;}

          4 DAO基类

          • JPA
            import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;@Repositorypublic interface DeptRepository extends JpaRepository {}
            • MPP
              import org.apache.ibatis.annotations.Mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;@Mapperpublic interface DeptMapper extends BaseMapper {}

              4.1 基类主要方法

              方法JpaRepositoryMPP BaseMapper
              插入一条记录save(T entity)insert(T entity)
              插入多条记录saveAll(Iterable entities)insertBatchSomeColumn(List entityList)
              根据 ID 删除deleteById(ID id)deleteById(Serializable id)
              根据实体(ID)删除delete(T entity)deleteById(T entity)
              根据条件删除记录-delete(Wrapper queryWrapper)
              删除(根据ID或实体 批量删除)deleteAllById(Iterable idList)
              根据 ID 修改save(T entity)updateById(T entity)
              根据条件更新记录-update(Wrapper updateWrapper)
              根据 ID 查询findById(ID id)selectById(Serializable id)
              查询(根据ID 批量查询)findAllById(Iterable ids)selectBatchIds(Collection query, CriteriaBuilder cb) { List predicates = new ArrayList(); predicates.add(cb.like(root.get("code"), dept.getCode() + "%")); predicates.add(cb.like(root.get("code"), '%' + dept.getCode() + "%")); return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); }};List deptList = deptRepository.findAll(Example.of(dept));

              除了equal、notEqual, 针对日期、数字类型,还有gt、ge、lt、le等常用比较符。

              4.2.3 MPP Wrpper

              MPP Wrapper类似于JPA的CriteriaBuilder,不过用法上更加便捷:

              Dept dept = new Dept();dept.setCode("100");dept.setName("Dept1");// select * from dept where code = '100' and name = 'Dept';Wrapper wrapper = Wrappers.lambdaQueryWrapper(detp);List deptList = deptRepository.selectList(wrapper); 

              默认是生成的条件都是 “=”,如果要设置其他比较符,需要单独设置Wrapper:

              Dept dept = new Dept();dept.setCode("100");dept.setName("Dept1");// select * from dept where code like '100%' and name like '%Dept1%';Wrapper wrapper = Wrappers.lambdaQueryWrapper()                        .likeRight(Dept::getCode, dept.getCode)                        .like(Dept::getName, dept.getName);List deptList = deptRepository.selectList(wrapper); 

              4.2.4 JPA Specification 与 MPP Wrpper的方法汇总

              方法JPA SpecificationMPP Wrpper
              等于 =equaleq
              不等于 notEqualne
              大于 >greaterThan, gtgt
              大于等于 >=greaterThanOrEqualTo, gege
              小于 // 调用此方法时,会自动生成 where code = ? 的条件Dept getByCode(String code);}p常用的方法命名有:/p tabletheadtrth align="left"关键字/thth align="left"方法命名/thth align="left"sql条件/th/tr/theadtbodytrtd align="left"Distinct/tdtd align="left"findDistinctByLastnameAndFirstname/tdtd align="left"select distinct …​ where x.lastname = ?1 and x.firstname = ?2/td/trtrtd align="left"And/tdtd align="left"findByNameAndPwd/tdtd align="left"where name= ? and pwd =?/td/trtrtd align="left"Or/tdtd align="left"findByNameOrSex/tdtd align="left"where name= ? or sex=?/td/trtrtd align="left"Is,Equals/tdtd align="left"findById, findByIdIs, findByIdEquals/tdtd align="left"where id= ?/td/trtrtd align="left"Between/tdtd align="left"findByIdBetween/tdtd align="left"where id between ? and ?/td/trtrtd align="left"LessThan/tdtd align="left"findByIdLessThan/tdtd align="left"where id ?
              BeforefindByIdBeforewhere id
              IsNullfindByNameIsNullwhere name is null
              isNotNull,NotNullfindByNameNotNullwhere name is not null
              LikefindByNameLikewhere name like ?
              NotLikefindByNameNotLikewhere name not like ?
              StartingWithfindByNameStartingWithwhere name like ‘?%’
              EndingWithfindByNameEndingWithwhere name like ‘%?’
              ContainingfindByNameContainingwhere name like ‘%?%’
              OrderByfindByIdOrderByXDescwhere id=? order by x desc
              NotfindByNameNotwhere name ?
              InfindByIdIn(Collection c)where id in (?)
              NotInfindByIdNotIn(Collection c)where id not in (?)
              TruefindByEnabledTuewhere enabled = true
              FalsefindByEnabledFalsewhere enabled = false
              IgnoreCasefindByNameIgnoreCasewhere UPPER(name)=UPPER(?)
              First,TopfindFirstByOrderByLastnameAscorder by lastname limit 1
              FirstN,TopNfindTop3ByOrderByLastnameAscorder by lastname limit 3

              5.2 MPP自定义方法 + 接口默认实现

              MyBatisPlus没有JPA那样可以根据接口的方法名自动组装查询条件,但是可以利用Java8的接口默认实现来达到同样的目的,只不过需要编写少量的代码:

              import org.apache.ibatis.annotations.Mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;@Mapperpublic interface DeptMapper extends BaseMapper {    default Dept getByCode(String code) {return selectOne(Wrappers.lambdaWrapper().eq(Dept::getCode, code));}}

              6 自定义SQL

              JPA支持通过@Query注解和XML的形式实现自定义SQL,而MyBatis支持通过@Select、@Delete、@Update、@Script注解和XML的形式实现自定义SQL。

              6.1 JPA

              JPA的自定义SQL分为JPQL(Java Persistence Query Language Java 持久化查询语言)和原生SQL两种。

              JPQL:

              import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.query.Param;@Repositorypublic interface DeptRepository extends JpaRepository {    @Query(value = "select d from Dept d where d.code = ?1")Dept getByCode(String code);    @Modifying    @Query(value = "delete from Dept d where d.code = :code")    int deleteByCode(@Param("code") String code);}

              原生SQL

              import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.query.Param;@Repositorypublic interface DeptRepository extends JpaRepository {    @Query(value = "SELECT * FROM dept WHERE name = ?1", countQuery = "SELECT count(*) FROM dept WHERE name = ?1", nativeQuery = true)    Page findByName(@Param("name") String name, Pageable pageable);}

              XML形式:

              /resource/META-INFO/orm.xml

                 select d from Dept d where d.code = ?1   DELETE FROM dept WHERE code = ?1

              6.2 MyBatis

              JPA的自定义SQL分为注解形式和XML形式

              注解形式:

              import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.baomidou.mybatisplus.core.metadata.IPage;@Mapperpublic interface DeptMapper extends BaseMapper {    @Select(value = "SELECT * FROM dept WHERE code = #{code}")Dept getByCode(@Param("code") String code);    @Delete("DELETE FROM dept WHERE code = #{code}")    int deleteByCode(@Param("code") String code);        @Select(value = "SELECT * FROM dept WHERE name = #{name}")    IPage findByName(@Param("name") String name, IPage page);}

              XML形式:

              /resource/mapper/DeptMapper.xml

              SELECT * FROM dept WHERE code = #{code}DELETE FROM dept WHERE code = #{code}SELECT * FROM dept WHERE name = #{name}

              7 表关联

              待补充

              8 其他

              对于简单的CRUD操作,JPA和MPP都提供了丰富的API简化开发人员的操作,但是有些差异化的地方需要总结下:

              比较点JPAMPP
              成熟度JPA毕竟是javax标准,成熟度自然高MyBatis成熟度也很高,但是MPP毕竟是国内个人维护,质量和成熟度相对还是比较低的,但是使用起来更加适配国内开发者的习惯
              自动DDLJPA可以根据Entity的定义自动更新实际数据库的DDL, 使用起来比较便利利用MPP的脚本自动维护或Flyway进行SQL脚本的自动执行
              实体关系使用@OneToMany、@OneToOne、@ManyTo@Many注解描述表与表之间的关联,查询时自动进行表的关联,并且支持更新和删除时自动级联到关联的实体使用和标签以及@One、@Many注解来映射结果集和Java对象,只支持查询,不支持更新和删除, 另外还有一个MyBatis-Plus-Join项目, 可以实现Java中表Join的操作。
              复杂SQL查询不太方便使用xml结构化语言 + 动态SQL 标签 可以实现非常复杂的SQL场景
              数据库差异使用自带的API和JPQL的话,是不用关心具体用什么数据库,但是用原生SQL的话无法解决数据库的差异使用自带API的话,基本上不需要关注数据库的差异,如果切换了不同类型的数据库,通过配置databaseIdProvider 就可以根据当前使用数据库的不同选择不同的SQL脚本
              学习曲线较为难,主要是思路的转变,使用JPA更加关注的是实体间的关系,表的结构会根据实体关系自动维护对于传统的关系型数据库的操作,MyBatisPlus可以与JQuery操作DOM元素那么顺手

              9 个人建议

              目前对比下来整体的感觉是JPA侧重数据建模,关注数据一致性,屏蔽SQL操作,MyBatis侧重构建灵活的SQL,而MyBatisPlus在MyBatis的基础上较少了日常的CRUD操作,JPA更适合事务性系统,MyBatisPlus更适合做分析型系统。

              个人是从SQL -> MyBatis -> MyBatisPlus的路线过来的,所以更习惯与用MPP解决数据的问题,在使用MPP的过程中,越来越发现自定义SQL用到越来越少,大部分场景下是可以用MPP的API组合来实现的,即便是MPP不支持多表关联,通过抽象视图的形式,也能达到单表查询的效果,只有在极限、特别复杂的情况下才会写SQL。

              这么看来,其实JPA也是能满足日常的开发需求的。但是从传统SQL向JPA的转变是需要一个过程的,就跟面向过程开发到面向对象的开发,是需要一个大的开发思维一个转变,可能需要在项目的实践中不断体会和适应。

上一篇:栀字读音与释义揭秘,探寻栀字的奥秘之旅

下一篇:图解Redis,Redis主从复制与Redis哨兵机制