Spring Data JPA 与 MyBatisPlus的比较

前言

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

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

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

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

POM依赖

JPA

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

MPP

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>

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;
}

DAO定义

基础CRUD

JPA

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;@Repository
public interface DeptRepository extends JpaRepository<Dept, Long> {
}

MPP

import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;@Mapper
public interface DeptMapper extends BaseMapper<Dept> {
}

基类主要方法

方法JpaRepositoryBaseMapper
插入一条记录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<? extends ID> ids)deleteBatchIds(Collection<?> idList)
根据 ID 修改save(T entity)updateById(T entity)
根据条件更新记录-update(Wrapper updateWrapper)
根据 ID 查询findById(ID id)selectById(Serializable id)
查询(根据ID 批量查询)findAllById(Iterable ids)selectBatchIds(Collection<? extends Serializable> idList)
根据条件查询一条记录-selectOne(Wrapper queryWrapper)
根据条件判断是否存在记录exists(Example example)exists(Wrapper queryWrapper)
根据条件查询总记录数count(Example example)selectCount(Wrapper queryWrapper)
根据条件查询全部记录findAll(Example example, Sort sort)selectList(Wrapper queryWrapper)
根据条件查询分页记录findAll(Example example, Pageable pageable)selectPage(P page, Wrapper queryWrapper)

Example、Specification VS Wrapper

JPA使用Example和Specification 类来实现范本数据的查询,而MPP使用QueryWrapper来设置查询条件

JPA Example
Dept dept = new Dept();
dept.setCode("100");
dept.setName("Dept1");// select * from dept where code = '100' and name = 'Dept1';
List<Dept> deptList = deptRepository.findAll(Example.of(dept)); 

默认是生成的条件都是 “=”,如果要设置其他比较符,需要使用ExampleMatcher

Dept dept = new Dept();
dept.setCode("100");
dept.setName("Dept1");// select * from dept where code like '100%' and name like '%Dept1%';
List<Dept> deptList = deptRepository.findAll(Example.of(dept, ExampleMatcher.matching().withMatcher("code", ExampleMatcher.GenericPropertyMatchers.startsWith()).withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains()))); 

Example仅能实现对字符串类型的匹配模式,如果要设置其他类型的字段,可以实现JpaSpecificationExecutor接口来完成:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;@Repository
public interface DeptRepository extends JpaRepository<Dept, Long>, JpaSpecificationExecutor<Dept>  {
}

增加以上接口后,会增加以下查询方法:

  • findOne(Specification spec)
  • findAll(Specification spec)
  • findAll(Specification spec, Pageable pageable)
  • count(Specification spec)
  • exists(Specification spec)

使用示例:

Dept dept = new Dept();
dept.setCode("100");
dept.setName("Dept1");// select * from dept where code like '100%' and name like '%Dept1%';
Specification<Dept> spec = new Specification<Dept>() {@Overridepublic Predicate toPredicate(Root<Dept> root, CriteriaQuery<?> query, CriteriaBuilder cb) {List<Predicate> predicates = new ArrayList<>();//  模糊查询(前缀匹配)if (dept.getCode() != null && !dept.getCode().isEmpty()) {predicates.add(cb.like(root.get("code"), dept.getCode() + "%"));}//  模糊查询if (dept.getName() != null && !dept.getName().isEmpty()) {predicates.add(cb.like(root.get("code"), '%' + dept.getCode() + "%"));}return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();}
};
List<Dept> deptList = deptRepository.findAll(Example.of(dept)); 

除了equalnotEqual, 针对日期、数字类型,还有gtgeltle等常用比较符。

自定义接口

JPA

JPA支持接口规范方法名查询,一般查询方法以 find、findBy、read、readBy、get、getBy为前缀,JPA在进行方法解析的时候会把前缀取掉,然后对剩下部分进行解析。例如:

@Repository
public interface DeptRepository extends JpaRepository<Dept, Long> {// 调用此方法时,会自动生成 where code = ? 的条件Dept getByCode(String code);
}

常用的方法命名有:

关键字方法命名sql where字句
DistinctfindDistinctByLastnameAndFirstnameselect distinct …​ where x.lastname = ?1 and x.firstname = ?2
AndfindByNameAndPwdwhere name= ? and pwd =?
OrfindByNameOrSexwhere name= ? or sex=?
Is,EqualsfindById, findByIdIs, findByIdEqualswhere id= ?
BetweenfindByIdBetweenwhere id between ? and ?
LessThanfindByIdLessThanwhere id < ?
LessThanEqualsfindByIdLessThanEqualswhere id <= ?
GreaterThanfindByIdGreaterThanwhere id > ?
GreaterThanEqualsfindByIdGreaterThanEqualswhere id > = ?
AfterfindByIdAfterwhere 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

MPP

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

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

自定义SQL

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

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;@Repository
public interface DeptRepository extends JpaRepository<Dept, Long> {@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;@Repository
public interface DeptRepository extends JpaRepository<Dept, Long> {@Query(value = "SELECT * FROM dept WHERE name = ?1", countQuery = "SELECT count(*) FROM dept WHERE name = ?1", nativeQuery = true)Page<Dept> findByName(@Param("name") String name, Pageable pageable);
}

XML形式:
/resource/META-INFO/orm.xml

<named-query name="Dept.getByCode"><query> select d from Dept d where d.code = ?1</query>
</named-query>
<named-native-query name="Dept.deleteByCode"><query> DELETE FROM dept WHERE code = ?1</query>
</named-native-query>

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;@Mapper
public interface DeptMapper extends BaseMapper<Dept> {@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<Dept> findByName(@Param("name") String name, IPage<Dept> page);
}

XML形式:
/resource/mapper/DeptMapper.xml

<select id = "getByCode", resultType = "Dept">SELECT * FROM dept WHERE code = #{code}
</select>
<delete id = "deleteByCode">DELETE FROM dept WHERE code = #{code}
</select>
<select id = "findByName">SELECT * FROM dept WHERE name = #{name}
</select>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/834696.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何给网页添加一个炫酷鼠标点击特效,鼠标特效源码分享(更多特效持续收集中...)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 鼠标特效 📒📝 火花特效🎈 源码📝 爱心特效🎈 源码📝 彩球爆炸特效🎈 源码📝 更多特效📖 介绍 📖 你是否厌倦了平淡无奇的网页交互?是否渴望为你的网站增添一抹亮色?本文将持续更新,与大家分享收集到的前…

区块链 | NFT 相关论文:Preventing Content Cloning in NFT Collections(二)

&#x1f436;原文&#xff1a; Preventing Content Cloning in NFT Collections &#x1f436;写在前面&#xff1a; 这是一篇 2023 年的 CCF-C 类&#xff0c;本博客只记录其中提出的方法。 F C o l l N F T \mathbf{F_{CollNFT}} FCollNFT​ and ERC-721 NFTs 在以太坊这样…

【数学建模】天然肠衣搭配问题衍生问题/线性规划限制条件建立问题

线性规划限制条件建立问题 前景回顾/提出问题回顾1回顾2/问题提出解决前提 解决方法坐标轴(区间)法总结 前景回顾/提出问题 回顾1 首先回顾一下DVD在线租赁问题 在 question2中&#xff0c;需要保证每个人都不会收到自己不喜欢的DVD&#xff0c;即客户在线订单数为0时候&…

Oracle中long和clob的区别和例子

在Oracle数据库中&#xff0c;LONG和CLOB&#xff08;Character Large Object&#xff09;都是用于存储大量字符数据的类型&#xff0c;但它们之间存在一些关键的区别。 存储方式&#xff1a; LONG&#xff1a;是以行存储的形式存储在数据行中的。当查询涉及到LONG列时&#…

umi6.x + react + antd的项目增加403(无权限页面拦截),404,错误处理页面

首先在src/pages下创建403&#xff0c;404&#xff0c;ErrorBoundary 403 import { Button, Result } from antd; import { history } from umijs/max;const UnAccessible () > (<Resultstatus"403"title"403"subTitle"抱歉&#xff0c;您无权…

进度条(小程序)

缓冲区的概念 缓冲区是内存中的一个临时存储区域&#xff0c;用来存放输入或输出数据。在标准 I/O 库中&#xff0c;缓冲区的使用可以提高数据处理的效率。例如&#xff0c;当向终端输出文本时&#xff0c;字符通常存储在缓冲区中&#xff0c;直到缓冲区满或者遇到特定条件时才…

FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流

《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书在第10章介绍了轻量级流媒体服务器MediaMTX&#xff0c;通过该工具可以测试RTSP/RTMP等流媒体协议的推拉流。不过MediaMTX的功能实在是太简单了&#xff0c;无法应用于真实直播的生产环境&#xff0c;真正能用于生产环境…

HarmonyOS开发之ArkTS使用:新建活动页面

目录 目录 引言 关于ArkTS 开发环境准备 新建项目 新建活动页面 编写ArkTS代码 注册页面 运行应用 最后 引言 随着HarmonyOS&#xff08;鸿蒙操作系统&#xff09;的不断发展&#xff0c;越来越多的前端开发者投入到这个全新的生态系统中。而在HarmonyOS的开发中&…

自我模拟面试

在面试中&#xff0c;你如何面对面试官呢&#xff1f; 我认为&#xff0c;对于面试官提出的问题&#xff0c;如果你不会&#xff0c;那就是不会。你的思考过程&#xff0c;实际上就是将你平时所学的&#xff0c;所了解的&#xff0c;在脑海中进行一次复习&#xff0c;就像当别…

线上副业新选择:宅家工作,4个项目助力增收!

在这个繁华世界&#xff0c;财富与智慧并驾齐驱。越来越多的人意识到&#xff0c;除了主业外&#xff0c;开拓一份副业是实现财富增长的重要途径。在此&#xff0c;我为大家精心挑选了几个值得一试的网上赚钱副业。 1&#xff0c;参与网络调查与问卷填写 随着大数据时代的到来…

[大师C语言(第三篇)]C语言函数参数背后的秘密

C语言函数参数背后的秘密&#xff08;一&#xff09; 在C语言中&#xff0c;函数是执行特定任务的一段代码&#xff0c;可以通过参数传递数据。函数参数是C语言中非常基本且重要的概念&#xff0c;但它们背后的技术原理可能并不为人所熟知。本文将深入探讨C语言函数参数的技术…

kkkkkkkkkkkk564

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习 &#x1f4dd;人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

UINXU

进入选项字节配置界面之后&#xff0c;从上到下框选的部分依次是读保护、用户配置部分、自定义的两个字节和写保护&#xff0c;这四个部分的配置也是可以直接点击就可以配置。 写保护点一下是四页同时打钩&#xff0c;对应选项字节里的一个位配置4个闪存页 配置完成之后点击…

YOLOv8 Tensorrt Python/C++部署详解

按照大佬的方法进行部署&#xff0c;但是中间出现了很多问题&#xff0c;这里进行一下总结。 YOLOv8 Tensorrt Python/C部署教程_yolo 安装tensorrt-CSDN博客https://blog.csdn.net/weixin_45747759/article/details/130341118 Monday-Leo/Yolov5_Tensorrt_Win10: A simple i…

Kafka从0到消费者开发

安装ZK Index of /zookeeper/zookeeper-3.9.2 下载安装包 一定要下载-bin的&#xff0c;不带bin的是源码&#xff0c;没有编译的&#xff0c;无法执行。-bin的才可以执行。 解压 tar -zxvf apache-zookeeper-3.9.2-bin.tar.gz 备份配置 cp zoo_sample.cfg zoo_sample.cfg-b…

物流集成商巨头-员工薪酬PK:今天国际、音飞存储,诺力股份

语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 以下内容为根据上市财报和公开数据整理&#xff0c;若有偏差&#xff0c;请联系小编修改。注意&#xff1a;各公司员…

ZYNQ实验--裸机程序固化

参考资料 正点原子《领航者 ZYNQ 之嵌入式 SDK 开发指南》详细的配置资料中都有介绍&#xff0c;本文只针对个人实验需求进行简要说明 固化流程 调试阶段是通过 JTAG 接口将 FPGA 配置文件和应用程序下载到 ZYNQ 器件中。但在实际应用中需要程序在上电或者复位时让程序自动运…

Adversarial Synthesis of Human Pose From Text # 论文阅读

URL https://arxiv.org/pdf/2005.00340 TD;DR 20 年 5 月来自高校的一篇论文&#xff0c;任务是用 GAN 生成 pose&#xff0c;目前 7 引用。 Model & Method 输入的是描述动作的 text&#xff0c;通过 text encoder&#xff08;本文用的是叫做 fastText 的方法&#…

vue-element-template优化升级dart-sass、pnpm

1、替换 node-sass 为 dart-sass - "node-sass": "^4.9.0","sass": "^1.75.0",替换css深度作用域写法 /deep/ >>># 替换为::v-deepVue&#xff1a;Node Sass VS. Dart Sass 2、替换npm为pnpm&#xff0c;需要补充一些依赖…

迷宫中离入口最近的出口

题目链接 迷宫中离入口最近的出口 题目描述 注意点 maze[i][j] 要么是 ‘.’ &#xff0c;要么是 ‘’entrance.length 2entrance 一定是空格子出口的含义是 maze 边界上的空格子entrance格子不算出口 解答思路 广度优先遍历找到走i步时所能到达的所有节点位置&#xff0…