Java21 + SpringBoot3集成Spring Data JPA

Java21 + SpringBoot3集成Spring Data JPA

文章目录

  • Java21 + SpringBoot3集成Spring Data JPA
    • 前言
    • 相关技术简介
      • ORM(Object-Relational Mapping,对象-关系映射)
      • JPA(Java Persistence API,Java持久层API)
      • Hibernate
      • Spring Data
      • Spring Data JPA
    • SpringBoot整合Spring Data JPA
      • 引入maven依赖
      • 修改配置文件
      • 定义Spring Data JPA配置类
      • 定义实体类
        • 定义数据库实体基类
        • 定义用户实体类
      • 定义Repository接口
      • 使用Repository接口
    • 总结
    • 附录
      • Spring Data JPA 基于方法名创建查询支持的关键词

前言

近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。

本项目为前后端分离开发,后端基于Java21SpringBoot3开发,后端使用Spring SecurityJWTSpring Data JPA等技术栈,前端提供了vueangularreactuniapp微信小程序等多种脚手架工程。

本文主要介绍JPA相关技术以及在项目中如何集成Spring Data JPA。

相关技术简介

ORM(Object-Relational Mapping,对象-关系映射)

ORM(Object-Relational Mapping) 即对象-关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中,一个类可以视作数据库中的一张表,类中的属性视作表中的字段,一个对象可以视为表中的一行记录。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM。也就是说ORM是建立了一个实体与数据库表的联系,这使得开发者对实体的直接操作而不是对数据库的操作,但操作实体也就等同于操作了数据库。主流的ORM框架有MyBatis、Hibernate、Spring Data JPA等。

JPA(Java Persistence API,Java持久层API)

JPA(Java Persistence API)是 Java EE 标准中的一部分,它通过提供提供一套对象关系模型(ORM)来帮助在开发应用过程中高效的管理关系型数据。和 JDBC 一样,JPA 本身并不是一个框架,只是一套标准接口,是ORM框架的标准和规范,目前比较成熟的 JPA 实现有 Hibernate、EclipseLink 等。

Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

JPA的目标是提供一种统一的、面向对象的数据访问方式,使开发人员能够更加方便地进行数据库操作,而不需要关注底层数据库的细节。它抽象了不同数据库之间的差异,提供了一套通用的API,使开发人员能够以相同的方式操作不同的数据库。

JPA的核心概念包括实体(Entity)、实体管理器(EntityManager)、持久化上下文(Persistence Context)等。开发人员可以通过注解或XML配置来定义实体类和数据库表之间的映射关系,然后使用EntityManager进行增删改查等数据库操作。

Hibernate

Hibernate是一个标准的ORM框架,实现Jpa接口。Hibernate着手解决如何实现映射的方案,是一种处理映射关系方法类框架。

JPA和Hibernate 的关系就像JDBC和JDBC 驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。

Spring Data

Spring Data是Spring Framework的一个子项目,它提供了一种简化数据访问层的方式。Spring Data支持多种数据存储技术,包括关系型数据库、NoSQL数据库、搜索引擎等。

通过使用Spring Data,开发人员可以更轻松地进行数据访问,同时还能够利用Spring Framework的其他功能,如依赖注入、面向切面编程等。

Spring Data提供了一组通用的API和实现,可以帮助开发人员快速、简便地访问各种类型的数据存储。

Spring Data JPA

Spring Data JPA是Spring Data项目中的一个模块,它提供了对JPA(Java Persistence API)的支持。

Spring Data JPA通过提供一组简化的API和自动化的实现,使得开发人员可以更轻松地进行数据库访问和操作。它减少了编写重复、繁琐的数据访问代码的工作量,同时还提供了一些方便的特性,如查询方法的自动生成、分页和排序的支持等。

使用Spring Data JPA,开发人员只需定义好实体类和接口,通过继承一些预定义的接口,就可以实现常见的数据访问操作,而无需编写具体的SQL语句。这样可以大大简化开发过程,提高开发效率。

Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,但底层还是使用了 Hibernate 的 JPA 技术实现。

SpringBoot整合Spring Data JPA

https://zhuanlan.zhihu.com/p/570922724

在下文中笔者将以实现对用户表SysUser的增删改查为例,介绍SpringBoot整合Spring Data JPA的详细过程。所示项目基于Java21SpringBoot3实现,数据库使用MySQL 5.7

引入maven依赖

pom.xml中添加MySQL和Spring Data JPA相关依赖,并引入Lombok用于简化代码。

<dependencies><!--Spring Data JPA Starter--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!--MySQL依赖包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version><optional>true</optional></dependency>
</dependencies>

修改配置文件

在配置文件application.yml或application.properties中增加数据库和jpa相关配置。以下代码使用的是yml文件。

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driver # JDBC驱动类url: jdbc:mysql://localhost:3306/db_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai # 数据库urlusername: developer # 数据库用户名password: abc123 # 数据库密码jpa:database: mysql # 数据库类型database-platform: org.hibernate.dialect.MySQL57Dialect # 数据库方言show-sql: true # 控制台打印SQLhibernate:ddl-auto: create # 根据实体类自动建表

上述配置中spring.jpa.hibernate.ddl-auto作用是根据实体类自动建表,无需手写ddl来建表。这样就使得开发者可以专注于实体类的设计,无需再去考虑建表SQL,可以提高开发效率。但此配置项更适合于开发环境时使用,不建议生产环境使用。

ddl-auto可选值如下:

  • none,默认值,无任何操作;
  • create,服务启动时没有表会新建表,有表则删除表和已有数据后重新建表;
  • create-drop,服务启动时没有表会新建表,有表则清空数据并删除后重新建表,服务停止时删除所有表和数据;
  • update,服务启动时没有表则新建表,有表则更新表结构,不清空已有数据;
  • validate,服务启动时会校验实体类和数据库表结构是否一致,不一致会报错。

定义Spring Data JPA配置类

定义一个配置类Bean,启用Spring Data JPA,也可以直接main方法所在类上直接添加@EnableJpaRepositories@EntityScan注解。

package com.demo.data.config;import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;/*** Spring Data JPA Bean配置* 启用Jpa,扫描指定包下的Repository类和指定包下的实体类*/
@Configuration
@EnableJpaRepositories(basePackages = {"com.demo.data.repo"})
@EntityScan(basePackages = "com.demo.data.model")
public class JpaConfig {
}

定义实体类

定义数据库实体基类

为了简化代码,可以将所有数据库实体类共有的属性提取出来,定义一个基础类。

/*** 数据库实体基类,声明数据库实体类共有属性*/
@Getter
@Setter
@MappedSuperclass
public abstract class BaseEntity implements Serializable {/*** ID,唯一标识列,使用主键自增策略*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;/*** 创建时间*/@CreatedDateprivate LocalDateTime createdTime;/*** 最后修改时间*/@LastModifiedDateprivate LocalDateTime lastModifiedTime;/*** 创建人ID*/private Long creatorId;/*** 最后修改人ID*/private Long lastModifierId;
}
  • @MappedSuperclass,表示一个类是某些实体类的超类,它不会直接映射为数据库表,但是可以被其他实体类继承,它的子类映射的数据库表中会包含它自身声明的属性。
  • @Id,用于声明一个实体类的属性映射为数据库的主键列,一个JPA实体类中必须要有一个使用@Id注解的属性。
  • @GeneratedValue,用于指定主键的生成策略,通过strategy属性来设置。
  • @CreatedDate,表示该字段为创建时间字段,执行insert语句前会自动赋值。
  • @LastModifiedDate,表示该字段为最后修改时间字段,执行insertupdate语句前会自动赋值。
定义用户实体类

用户实体类SysUser中还用到了部门类Department,使用Department主要是为了介绍@Transient注解,本文不再给出其详细代码。它同样继承自BaseEntity,有部门编号(code)部门名称(name)两个属性。

/*** 用户实体类*/
@Getter
@Setter
@Entity(name = "sys_user")
public class SysUser extends BaseEntity {/*** 用户名*/@Column(unique = true)private String username;/*** 密码*/private String password; /*** 电话*/private String phone;/*** 个人介绍*/@Lobprivate String introduce;/*** 所属部门ID*/private Long departmentId;/*** 所属部门*/@Transientprivate Department department;
}
  • @Entity,表示该类是一个实体类,可以映射为数据库表。name属性用于自定义表名,不设置name属性时默认会取类名转化为全小写+下划线分隔的字符串作为表名,比如类名为SysUser则默认映射的表名为sys_user

    在使用了@Entity注解的类中,必须要有一个使用@Id注解修饰的属性。
    在使用了@Entity注解的类中,所有的属性都会被映射为数据库表中的字段,除非属性上使用了@Transient注解。

  • @Column,表示该属性是一个表中的字段,unique = true可以在对应字段上定义唯一约束,在有@Entity注解修饰的类中,属性上不加@Column注解也可以被映射为字段。

  • @Lob,表示该属性需要映射成数据库支持的大对象类型的字段,比如Clob或者Blob

  • @Transient,表示该属性并非一个到数据库表中字段的映射,ORM框架映射时会忽略该属性。

定义Repository接口

JPA中的Repository可以理解为DAO(Data Access Object),即数据操纵对象。一个JPA的实体类需要有一个对应的Repository,用于操作该实体类所映射的数据库表。Repository可以仅仅是一个接口无需创建它的实现类,需要继承JpaRepository<T, ID>接口,T是实体类,ID是实体类中@Id修饰的属性的类型。程序启动时Spring Data JPA会自动生成该接口的实现,并注册为Spring Bean。

JpaRepository中定义了一系列最基本的CURD方法,开发者可以直接使用,也可以根据业务需求自定义查询方法。Spring Data JPA支持多种查询定义方式,主要包括:

  • 基于方法名创建查询,可以根据方法名中的关键词构造出实际的查询SQL,在附录中给出了Spring Data JPA所支持的关键词;
  • 基于@Query注解创建JPQL查询或者原生SQL查询,nativeQuery属性设置为true时表示使用原生SQL
  • 基于Specification构造动态查询,此方式需要Repository继承JpaSpecificationExecutor<T>接口,T是实体类;

以下代码是使用不同方法创建查询的示例,基于Specification的查询方式在下一章节中给出。

/*** 用户表Repository*/
public interface SysUserRepository extends JpaRepository<SysUser, Long>, JpaSpecificationExecutor<SysUser> {/*** 根据username精确查询*/Optional<SysUser> findByUsername(String username);@Query("select u from SysUser u where u.username = ?1")Optional<SysUser> findByUsername2(String username);
}

使用Repository接口

在前文中我们已经定义好了一个用户实体类SysUser和一个用户表的DAO接口SysUserRepository,下面我们就来使用它们完成简单的增删改查操作。以下代码中我们定义了一个服务类接口SysUserService和它的具体实现SysUserServiceImpl

public interface SysUserService {/*** 分页查询*/Page<SysUser> page(Pageable pageable);/*** 查询全部用户*/List<SysUser> list();/*** 根据ID查询*/SysUser retrieve(Long id);/*** 根据用户名查询*/SysUser findByUsername(String username);/*** 新增用户*/SysUser create(SysUser user);/*** 修改用户*/SysUser update(SysUser user);/*** 批量删除用户*/void remove(List<Long> ids);
}
@Service
public class SysUserServiceImpl implements SysUserService {private final SysUserRepository userRepository;public SysUserServiceImpl(SysUserRepository userRepository) {this.userRepository = userRepository;}@Overridepublic Page<SysUser> page(Pageable pageable) {return userRepository.findAll(pageable);}@Overridepublic List<SysUser> list() {return userRepository.findAll();}@Overridepublic SysUser retrieve(Long id) {return userRepository.findById(id).orElse(null);}@Overridepublic SysUser findByUsername(String username) {// 使用基于方法名定义的查询return userRepository.findByUsername(username).orElse(null);// 使用基于@Query定义的查询// return userRepository.findByUsername2(username).orElse(null);// 使用Specification查询// return userRepository.findOne(//         (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("username").as(String.class), username)// ).orElse(null);}@Overridepublic SysUser create(SysUser user) {return userRepository.save(user);}@Overridepublic SysUser update(SysUser user) {if (userRepository.findById(user.getId()).isEmpty()) {throw new RuntimeException("未查询到数据");}return userRepository.save(user);}@Overridepublic void remove(List<Long> ids) {userRepository.deleteAllById(ids);}
}

总结

在本文中,我们一起学习了与Spring Data JPA相关的技术简介,学习了如何基于Java21和SpringBoot3整合Spring Data JPA,也学习了JPA Repository的简单使用方法,如有错误,还望批评指正。

在后续实践中我也是及时更新自己的学习心得和经验总结,希望与诸位看官一起进步。

附录

Spring Data JPA 基于方法名创建查询支持的关键词

数据来源:Spring Data JPA 3.2.2官方文档https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.query-methods.query-creation

关键词示例对应的JPQL语句
DistinctfindDistinctByLastnameAndFirstnameselect distinct … where x.lastname = ?1 and x.firstname = ?2
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is, EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNull, NullfindByAge(Is)Null… where x.age is null
IsNotNull, NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstname) = UPPER(?1)

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

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

相关文章

新版K8s:v1.28拉取Harbor仓库镜像以及本地镜像(docker弃用改用containerd,纯纯踩坑)

目录 一、项目概述二、环境三、项目样式Harborkuboard运行样式 四、核心点Harbor安装config.toml文件修改(containerd)ctr、nerdctl相关命令kuboard工作负载 五、总结 一、项目概述 使用Kuboard作为k8s集群的管理平台&#xff0c;Harbor作为镜像仓库&#xff0c;拉取Harbor镜像…

【kafka】记录用-----------1

主题&#xff08;topic&#xff09;&#xff1a;消息的第一次分类 根据人为的划分条件将消息分成不同的主题 主题的划分是人为的根据不同的任务情景去划分 比如&#xff0c;我们有两个主题&#xff0c;一个是"订单"&#xff0c;另一个是"库存"。每个主题代…

24号资源——程序:电力系统程序集合已提供下载资源

24号资源&#xff1a;程序集合包含17个程序&#xff08;经典电力系统经济调度程序&#xff1b;2解决带储&#xff1b;3智能微电网PSO优化算法&#xff1b;微电网调度等等见资源描述&#xff09;资源-CSDN文库https://download.csdn.net/download/LIANG674027206/88752141&#…

ruoyi-cloud—若依微服务打包部署

1. 前端端口修改 2. 后端端口修改 &#xff08;1&#xff09;修改ruoyi-gateway服务中的bootstrap.yml的port端口 &#xff08;2&#xff09;修改ruoyi-ui中的vue.confing.js的target中的端口 3. 后端部署 (1) 在本地电脑上代码界面上打包后端 在ruoyi项目的bin目录下执行pa…

迭代器模式介绍

目录 一、迭代器模式介绍 1.1 迭代器模式定义 1.2 迭代器模式原理 1.2.1 迭代器模式类图 1.2.2 模式角色说明 1.2.3 示例代码 二、迭代模式的应用 2.1 需求说明 2.2 需求实现 2.2.1 抽象迭代类 2.2.2 抽象集合类 2.2.3 主题类 2.2.4 具体迭代类 2.2.5 具体集合类 …

【动态规划】【数学】【C++算法】18赛车

作者推荐 视频算法专题 本文涉及知识点 动态规划 数学 LeetCode818赛车 你的赛车可以从位置 0 开始&#xff0c;并且速度为 1 &#xff0c;在一条无限长的数轴上行驶。赛车也可以向负方向行驶。赛车可以按照由加速指令 ‘A’ 和倒车指令 ‘R’ 组成的指令序列自动行驶。 当…

软件工程应用题汇总

绘制数据流图(L0/L1/L2) DFD/L0&#xff08;基本系统模型&#xff09; 只包含源点终点和一个处理(XXX系统) DFD/L1&#xff08;功能级数据流图&#xff09;在L0基础上进一步划分处理(XXX系统) 个人理解 DFD/L2&#xff08;在L1基础上进一步分解后的数据流图&#xff09; 数据…

flex布局(3)

九、骰子 *{margin:0;padding: 0;box-sizing: border-box; } .flex{display: flex;flex-flow: row wrap;justify-content: space-between;align-items: center;align-content: space-between;padding:20px; } .touzi{width: 120px;height: 120px;background-color: aliceblue;…

canvas绘制美队盾牌

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

陶瓷碗口缺口检测-图像分割

图像分割 由于对碗口进行缺口检测&#xff0c;因此只需要碗口的边界信息。得到陶瓷碗区域填充后的图像&#xff0c;对图像进行边缘检测。这是属于图像分割中的内容&#xff0c;在图像的边缘中&#xff0c;可以利用导数算子对数字图像求差分&#xff0c;将边缘提取出来。 本案…

React 基于Ant Degisn 实现table表格列表拖拽排序

效果图&#xff1a; 代码&#xff1a; myRow.js import { MenuOutlined } from ant-design/icons; import { DndContext } from dnd-kit/core; import { restrictToVerticalAxis } from dnd-kit/modifiers; import {arrayMove,SortableContext,useSortable,verticalListSorti…

探案录 | 人大金仓一个底座+多场景应用

近日&#xff0c;金仓大世界发布了《2023城市数字经济发展报告》&#xff0c;福尔摩斯•K从报告中抓住了三大重点&#xff1a;第一&#xff0c;数字经济规模超过50万亿元&#xff0c;占GDP比重提升至41.5%&#xff1b;第二&#xff0c;数字经济与实体经济融合愈发紧密&#xff…

阿赵UE学习笔记——10、Blender材质和绘制网格体

阿赵UE学习笔记目录   大家好&#xff0c;我是阿赵。   之前介绍了虚幻引擎的材质和材质实例。这次来介绍一个比较有趣的内置的Blender材质。   在用Unity的时候&#xff0c;我做过一个多通道混合地表贴图的效果&#xff0c;而要做过一个刷顶点颜色混合地表和水面的效果。…

【深度学习目标检测】十六、基于深度学习的麦穗头系统-含GUI和源码(python,yolov8)

全球麦穗检测是植物表型分析领域的一个挑战&#xff0c;主要目标是检测图像中的小麦麦穗。这种检测在农业领域具有重要意义&#xff0c;可以帮助农民评估作物的健康状况和成熟度。然而&#xff0c;由于小麦麦穗在视觉上具有挑战性&#xff0c;准确检测它们是一项艰巨的任务。 全…

记redis5.x在windows上搭建集群(六主六从)

六个运行端口 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 1、安装redis,文章太多不多BB 2、复制六份redis文件夹出来改名 3、修改每一份的配置文件 redis.windows.conf 修改为以下格式&#xff1a; #运行端口 port…

CAN记录仪在矿卡中的应用

CAN数据记录仪在矿卡中主要用于记录和监控车辆的运行数据&#xff0c;以保障安全和提高运营效率。那么就需要记录整车数据来进行车辆诊断分析&#xff0c;查找问题解决问题。 CAN数据记录仪可以记录矿卡的各种运行参数&#xff0c;如发动机转速、车速、制动状态、转向状态、油…

《WebKit 技术内幕》之二: HTML 网页和结构

第二章 HTML 网页和结构 HTML网页是利用HTML语言编写的文档&#xff0c;HTML是半结构化的数据表现方式&#xff0c;它的结构特征可以归纳为&#xff1a;树状结构、层次结构和框结构。 1.网页构成 1.1 基本元素和树状结构 HTML网页使用HTML语言撰写的文档&#xff0c;发展到今…

渗透测试之Kali如何利用CVE-2019-0708漏洞渗透Win7

环境: 1.攻击者IP:192.168.1.10 系统: KALI2022(vmware 16.0) 2.靶机IP:192.168.1.8 系统:Windows 7 6.1.7601 Service Pack 1 Build 7601 已开启远程协助RDP服务开启了3389端口 问题描述: KALI 如何利用CVE-2019-0708漏洞渗透Win7 解决方案: 1.打开kali,msf搜索…

使用WAF防御网络上的隐蔽威胁之SSRF攻击

服务器端请求伪造&#xff08;SSRF&#xff09;攻击是一种常见的网络安全威胁&#xff0c;它允许攻击者诱使服务器执行恶意请求。与跨站请求伪造&#xff08;CSRF&#xff09;相比&#xff0c;SSRF攻击针对的是服务器而不是用户。了解SSRF攻击的工作原理、如何防御它&#xff0…

redis数据安全(一)数据持久化

一、Redis数据安全措施: 1、将数据持久化至硬盘 2、将数据复制至其他机器&#xff1b; 复制是在数据持久化的基础上进行的。 二、将数据持久化至硬盘 1、介绍&#xff1a;Redis是一个基于内存的数据库&#xff0c;它的数据是存放在内存中&#xff0c;内存有个问题就是关闭…