当前位置: 首页 > news >正文

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>

相关文章:

Spring Data JPA 与 MyBatisPlus的比较

前言 JPA&#xff08;Java Persistence API&#xff09;和MyBatis Plus是两种不同的持久化框架&#xff0c;它们具有不同的特点和适用场景。 JPA是Java官方的持久化规范&#xff0c;它提供了一种基于对象的编程模型&#xff0c;可以通过注解或XML配置来实现对象与数据库的映射…...

【C++】STL-list的使用

目录 1、list的使用 1.1 list的构造 1.2 list的遍历 1.3 list capacity 1.4 list element access 1.5 容量相关 list是一个带头双向循环链表 1、list的使用 1.1 list的构造 1.2 list的遍历 list只有两种遍历方式&#xff0c;因为没有operator[] 因为list的双向链表&am…...

进度条(小程序)

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

PyCharm安装教程(超详细图文教程)

一、下载和安装 1.进入PyCharm官方下载&#xff0c;官网下载地址&#xff1a; https://www.jetbrains.com/pycharm/download/ 专业版安装插件放网盘了&#xff0c;网盘下载即可&#xff1a;itcxy.xyz/229.html2.安装 1.下载后找到PyCharm安装包&#xff0c;然后双击双击.ex…...

金蝶BI应收分析报表:关于应收,这样分析

这是一张出自奥威-金蝶BI方案的BI应收分析报表&#xff0c;是一张综合运用了筛选、内存计算等智能分析功能以及数据可视化图表打造而成的BI数据可视化分析报表&#xff0c;可以让企业运用决策层快速知道应收账款有多少&#xff1f;账龄如何&#xff1f;周转情况如何&#xff1f…...

salmon使用体验

文章目录 salmon转录本定量brief模式一&#xff1a;fastq作为输入文件需要特别注意得地方 模式二&#xff1a; bam文件作为输入 salmon转录本定量 brief 第一点是&#xff0c;通常说的转录组分析其中有一项是转录本定量&#xff0c;这是一个很trick的说话&#xff0c;说成定量…...

Ubuntu 20.04 安装 Ansible

使用官方的 Ubuntu PPA 更新包列表&#xff1a; apt update安装软件属性常用命令 apt install software-properties-common添加 Ansible PPA 到系统&#xff1a; add-apt-repository --yes --update ppa:ansible/ansible再次更新包列表以包括新添加的 PPA&#xff1a; apt …...

TypeScript学习笔记:强类型JavaScript的优雅之旅

在前端开发领域&#xff0c;JavaScript以其灵活性和广泛的支持度成为无可争议的王者。然而&#xff0c;随着项目规模的增长&#xff0c;JavaScript的动态类型特性开始暴露出一些问题&#xff0c;比如代码的可维护性、类型错误难以提前发现等。为了解决这些问题&#xff0c;Micr…...

监控异地组网怎么组网?

监控异地组网是指在不同地域的网络环境下&#xff0c;实现对监控设备的远程访问和管理。在传统的网络环境下&#xff0c;由于网络限制和设备配置等问题&#xff0c;监控设备的远程访问往往受到一定的限制和困扰。为了解决这个问题&#xff0c;引入了天联组网技术&#xff0c;实…...

将本地托管模型与 Elastic AI Assistant 结合使用的好处

作者&#xff1a;来自 Elastic James Spiteri, Dhrumil Patel 当今公共部门组织利用生成式人工智能解决安全挑战的一种方式。 凭借其筛选大量数据以发现异常模式的能力&#xff0c;生成式人工智能现在在帮助团队保护其组织免受网络威胁方面发挥着关键作用。 它还可以帮助安全专…...

Linux的内核态和用户态

一、Linux操作系统运行在两种不同的运行模式下&#xff1a;内核态&#xff08;Kernel Mode&#xff09;和用户态&#xff08;User Mode&#xff09; 内核态&#xff08;Kernel Mode&#xff09;&#xff1a; 内核态也称为特权模式或系统模式&#xff0c;是操作系统内核执行代码…...

springboot利用Redis的Geo数据类型,获取附近店铺的坐标位置和距离列表

文章目录 GEO介绍GEO命令行应用添加地理坐标位置获取指定单位半径的全部地理位置列表springboot 的实际应用 GEO介绍 在Redis 3.2版本中&#xff0c;新增了一种数据类型&#xff1a;GEO&#xff0c;它主要用于存储地理位置信息&#xff0c;并对存储的信息进行操作。 GEO实际上…...

Vitis HLS 学习笔记--理解串流Stream(2)

目录 1. 简介 2. 极简的对比 3. 硬件模块的多次触发 4. 进一步探讨 do-while 5. 总结 1. 简介 在这篇博文中《Vitis HLS 学习笔记--AXI_STREAM_TO_MASTER-CSDN博客》&#xff0c;我分享了关于 AXI Stream 接口的实际应用案例。然而&#xff0c;尽管文章中提供了代码示例&…...

Golang | Leetcode Golang题解之第80题删除有序数组中的重复项II

题目&#xff1a; 题解&#xff1a; func removeDuplicates(nums []int) int {n : len(nums)if n < 2 {return n}slow, fast : 2, 2for fast < n {if nums[slow-2] ! nums[fast] {nums[slow] nums[fast]slow}fast}return slow }...

uniapp自定义websocket类实现socket通信、心跳检测、连接检测、重连机制

uniapp自定义websocket类实现socket通信、心跳检测、检测连接、重连机制&#xff0c;仿vue-socket插件功能实现发送序列号进行连接检测&#xff0c;发送消息时42【key,value】格式&#xff0c;根据后端返回数据和需要接收到的数据做nsend与onSocketMessage的修改 //使用socket…...

Hive UDTF之explode函数、Lateral View侧视图

Hive UDTF之explode函数 Hive 中的 explode() 函数是一种用于处理数组类型数据的 User-Defined Table-Generating Function (UDTF)。它将数组拆分成多行&#xff0c;每个数组元素对应生成的一行数据。这在处理嵌套数据结构时非常有用&#xff0c;例如处理 JSON 格式的数据。 …...

智慧公厕打造智慧城市新标杆

公共厕所作为城市基础设施的重要组成部分&#xff0c;直接关系到市民的生活品质和城市形象。传统的公厕管理方式存在着许多问题&#xff0c;如环境脏乱、清洁不及时等&#xff0c;给市民带来了诸多不便和不满。而智慧公厕作为一种全新的管理模式&#xff0c;通过物联网、大数据…...

字节发布文生图模型PuLID:高效身份ID特征定制,单张图像克隆AI虚拟分身

前言 字节研究团队近日提出了一种新型的文生图身份ID定制方法PuLID(Pure and Lightning ID Customization)。相较于传统的微调方法&#xff0c;PuLID无需复杂的参数优化就可以实现高效的身份ID定制&#xff0c;且能最大程度减少对原始模型行为的干扰。 PuLID是通过将轻量级的…...

SpringBoot启动流程分析之创建SpringApplication对象(一)

SpringBoot启动流程分析之创建SpringApplication对象(一) 目录&#xff1a; 文章目录 SpringBoot启动流程分析之创建SpringApplication对象(一)1、SpringApplication的构造方法1.1、推断应用程序类型1.2、设置Initializers1.3、设置Listener1.4、推断main方法所在类 流程分析…...

SSH简介 特点以及作用

引言 SSH&#xff08;Secure Shell&#xff09;是一种用于安全远程访问和数据传输的网络协议。它提供了一种安全的机制&#xff0c;使得用户可以在不安全的网络中安全地进行远程登录、命令执行和文件传输。SSH通过加密技术和认证机制来保护数据的安全性&#xff0c;防止数据在…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...