如何在 Spring Boot 中 读写数据
写在前面:2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上,内容详细,图文并茂,有需要学习的朋友可以Star一下! GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master
1 JPA
JPA全称为Java Persistence API(Java持久层API),它是在 jdk 5中提出的Java持久化规范。它为开发人员提供了一种对象/关联映射工具,实现管理应用中的关系数据,从而简化Java对象的持久化工作。很多ORM框架都是实现了JPA的规范,比如:Hibernate、EclipseLink 等。
1.1 Java 持久层框架
Java 持久层框架访问数据库的方式分为两种。一种以 SQL 为核心,封装一定程度的 JDBC 操作,比如: MyBatis 框架。另一种是以 Java 实体类为核心,建立实体类和数据库表之间的映射关系,也就是ORM框架,比如:Hibernate、Spring Data JPA。
如何在 Spring Boot 中 读写数据
1.2 JPA 规范
- ORM映射元数据:JPA支持XML和注解两种元数据形式。元数据用于描述对象和表之间的映射关系,框架会据此将实体对象持久化到数据库表中。
- JPA 的API:用来操作实体对象,执行CRUD操作。对于简单的 CRUD 操作,开发人员可以不用写代码。
- JPQL查询语言:以面向对象的方式来查询数据。
1.3 Hibernate
Hibernate 框架可以将应用中的数据模型对象映射到关系数据库表的技术。
JPA 是规范,而Hibernate是JPA的一种实现框架。
2 Spring Data JPA
Spring Data JPA 在实现了JPA规范的基础上封装的一套 JPA 应用框架。使用Spring Data JPA能够在不同的ORM框架之间方便地进行切换而不需要更改代码。Spring Data JPA 的目标是统一ORM框架的访问持久层操作,来提高开发效率。
Spring Data JPA只是一个抽象层,主要用于减少为各种持久层存储实现数据访问层所需的样板代码量。它的 JPA 实现层就是采用 Hibernate 框架实现的。
如何在 Spring Boot 中 读写数据
2.1 引入依赖包
在 Spring Boot 应用中,只需要打开 pom.xml 加入一个 Spring Data JPA 依赖即可。 这个依赖不仅会引入 Spring Data JPA ,还会传递性地将 Hibernate 作为 JPA 实现引入进来。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2.2 实体类注解
(1)@Entity
类注解,用于标识这个实体类是一个JPA实体。
(2)@Table(name = "自定义表名")
类注解,用于自定义实体类在数据库中所对应的表名,默认是实体类名。特别是那些被作为数据库关键字的实体类名,就会用到这个注解来指定表名。
(3)@Id
类变量注解,用于指定主键。
(4)@GeneratedValue
类变量注解,用于指定主键的生成策略。
它包含strategy属性,具体说明如下:
如何在 Spring Boot 中 读写数据
(5)@Basic
指定类变量读取方法到数据库表字段的映射关系。对于没有任何特殊注解的getXxxx()方法,默认带有 @Basic 注解。也就是说,除非特殊情况,否则所有的类变量都带有 @Basic 注解,这些变量都映射到指定的表字段中。
@Basic 注解有一个 fetch 属性用于表示读取策略。策略有两种EAGER和LAZY,它们分别表示为主动读取与懒加载。默认为 EAGER。
(6)@Column
表示列的说明,如果字段名与列名相同,则可以省略。
@Column 注解拥有以下属性:
如何在 Spring Boot 中 读写数据
(7)@Transient
类变量注解,表示该变量不是一个到数据库表的字段映射。因为类变量的默认注解是 @Basic,所以某些场景下的非持久化类变量就会用到该注解。
(8)@Temporal
类变量注解(也可用在 getXxx 方法上),表示时间格式。具体说明如下:
如何在 Spring Boot 中 读写数据
Craig Walls 举了这样一个实体类代码示例:
@Data
@RequiredArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@Entity
public class Ingredient {
@Id
private final String id; private final String name;
private final Type type;
public static enum Type {
WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
}}
示例中除了应用 @Entity 与 @Id 注解之外,还在类级别添加了 @NoArgsConstructor 注解 。因为 JPA 需要实体类提供一个无参构造器,所以这里利用 Lombok 的 @NoArgsConstructor 注解来生成这个构造器。
@NoArgsConstructor 注解还可以将这个无参构造器私有化(access = AccessLevel.PRIVATE),这样外部就不能直接调用。
因为这个类的变量 id、name 与 type 还未初始化,所以我们还需要把 force 设置为 true,将其初始化为 null。
虽然 @Data 注解会为我们添加一个有参构造器,但因为之前添加了 @NoArgsConstructor 注解,所以有参构造器就没了。因此,必须再添加一个 @RequiredArgsConstructor 注解,强制生成一个有参构造器。
2.3 实体类关系注解
Spring Data JPA 有四种关系注解,它们分别是 @OneToOne、@OneToMany、@ManyToOne 和@ManyToMany。
这四种关系注解都有 fetch 与 cascade 两种属性。
fetch 属性用于指定数据延迟加载策略:
如何在 Spring Boot 中 读写数据
cascade 属性用于指定级联策略: 策略 | 说明 --- | --- CascadeType.PERSIST | 级联持久化;保存父实体时,也会同时保存子实体。 CascadeType.MERGE | 级联合并;修改了子实体,保存父实体时也会同时保存子实体(常用)。 CascadeType.REMOVE | 级联删除;删除父实体时,会级联删除关联的子实体。 CascadeType.REFRESH | 级联刷新;获取父实体的同时也会重新获取最新的子实体。 CascadeType.ALL | 以上四种策略 无 | 默认值
因为这四种注解只能表示实体之间几对几的关系,指定与所操作实体相关联的数据库表中的列字段,就需要用到 @JoinColumn 注解。
如何在 Spring Boot 中 读写数据
假设有这样的一组实体关系。一个用户拥有一个密码;而一个用户属于一个部门,一个部门下拥有多个用户;一个用户可以拥有多个角色,而一个角色下也可以包含多个用户。
(1)@OneToOne
@OneToOne 用来表示一对一的关系,放置在主导类上。比如用户类会有一个指定密码表的主键 pwd_id,将 @OneToOne 放置在用户类的 pwd 字段上,就可以表示用户类与密码类是一对一的关系,并且主导类是用户类。
@OneToOne
@JoinColumn(name = "pwd_id")
private Password pwd;
也可以不使用 @JoinColumn,Hibernate 会自动在用户表生成关联字段,字段默认的命名规则为 “附属类名_附属主键”,如:password_id。
有时候会看到注解 @PrimaryKeyJoinColumn(name = "...") ,其实它本质上是 @Id 与 @JoinColumn(name = "...") 的组合体。
(2)@OneToMany
在分析用户与部门之间关系时,会发现一个用户只能属于一个部门,而一个部门可以包含有多个用户。所以,如果站在部门的角度来看
在分析用户与部门之间的关系时,一个员工只能属于一个部门,但是一个部门可以包含有多个员工,如果我们站在部门的角度来看,部门与员工之间就是一对多的关系,在部门实体类 Department 上添加如下注解:
1. @OneToMany
2. @JoinColumn(name = "department_id")
3. private List<User> user;
如果不指定@JoinColumn 注解,Hibernate会自动生成一张中间表来对用户和部门进行绑定,这张中间表默认的命名规则为:实体类表名_实体类中指定的属性名。例如,部门表名为 t_department ,部门实体类中关联的用户集合属性名为 user,则默认生成的中间表名为:t_department_user。 在实践中,我们推荐使用@JoinTable注解来直接指定中间表:
@OneToMany
@JoinTable(name = " t_department_user ", joinColumns = {
@JoinColumn(name = "department_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") })
private List<User> users;
@JoinColumn 中的 name 属性用于指定当前实体类(部门)所对应表的关联 ID;inverseJoinColumns 属性用于指定所关联的实体类表(员工)的关联 ID,里面内嵌了 @JoinColumn 注解。
(3)@ManyToOne(多对一)
如果我们站在用户的角度来看待用户与部门之间的关系时,它们之间就变成了多对一的关系(多个用户隶属于一个部门),在用户实体类 User 上添加如下注解:
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
(4)@ManyToMany(多对多)
用户与角色之间是多对多的关系,因为一个用户可以拥有多个角色,而一个角色也可以隶属于多个员工。多对多关系一般通过创建中间表来进行关联,这时就会用到 @JoinTable注解。
在用户实体类中添加如下注解:
@ManyToMany
@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = {
@JoinColumn(name = "role_id") })
private List<Role> roles;
在角色实体类中添加如下注解:
@ManyToMany
@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "role_id") }, inverseJoinColumns = {
@JoinColumn(name = "user_id") })
private List<User> users;
- css自动换行如何设置?url太长会撑开页面
- Histogram of Oriented Gridients(HOG) 方向梯度直方图
- 动态规划系列之最长递增子序列问题解答
- Git SSH Key 生成步骤
- 如何将wordpress所有文章批量改为已发布状态
- dedecms提取某栏目及子栏目名称到首页怎么弄
- Bootstrap速学教程之简要介绍
- Ubuntu 安装 JDK8 的两种方式
- git命令-切换分支
- 如何让dedecms文章点击量增加一定的数值
- dedecms自增标签[field:global.autoindex/]的运用
- dedecms调用副栏目文章怎么操作
- 12个非常有用的JavaScript技巧
- 使用JPA中@Query 注解实现update 操作
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- mapboxGL中popup遮挡的优化
- SQL注入的基本步骤
- JS 变量作用域导致的一个坑
- 池化技术到达有多牛?看了线程和线程池的对比吓我一跳!
- Nginx 跨域 add_header 403状态下无效
- Cannot set property 'branchdata' of undefined
- 【每日一题】27. Remove Element
- 【CPP】《程序员面试金典》习题(1)——数组与字符串
- 【CPP】《程序员面试金典》习题(2)——链表
- 【CPP】《程序员面试金典》习题(3)——栈和队列
- PPYOLO:2020不容错过的目标检测调参Tricks
- 【笔记】《C++Primer》—— 第11章:关联容器
- 【笔记】《C++Primer》—— 第12章:动态内存
- 【笔记】《C++Primer》—— 第13章:拷贝控制
- 【笔记】《C++Primer》—— 第16章:模板与泛型编程