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

【Spring Boot】Java 持久层 API:JPA

Java 持久层 API:JPA

  • 1.Spring Data
    • 1.1 主要模块
    • 1.2 社区模块
  • 2.JPA
  • 3.使用 JPA
    • 3.1 添加 JPA 和 MySQL 数据库的依赖
    • 3.2 配置数据库连接信息
  • 4.了解 JPA 注解和属性
    • 4.1 常用注解
    • 4.2 映射关系的注解
    • 4.3 映射关系的属性
  • 5.用 JPA 构建实体数据表

1.Spring Data

Spring Data 是 Spring 的一个子项目,旨在统一和简化各类型数据的持久化存储方式,而不拘泥于是关系型数据库还是 NoSQL 数据库。

无论是哪种持久化存储方式,数据访问对象Data Access ObjectsDAO)都会提供对对象的增加、删除、修改和查询的方法,以及排序和分页方法等。

Spring Data 提供了基于这些层面的统一接口(如:CrudRepository、PagingAndSortingRepository),以实现持久化的存储。

Spring Data 包含多个子模块,主要分为主模块和社区模块。

1.1 主要模块

模块名称
作用
Spring Data Commons提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化。
Spring Data JDBC提供了对 JDBC 的支持,其中封装了 JDBCTemplate。
Spring Data JDBC Ext提供了对 JDBC 的支持,并扩展了标准的 JDBC,支持 Oracle RAD、高级队列和高级数据类型。
Spring Data JPA简化创建 JPA 数据访问层和跨存储的持久层功能。
Spring Data KeyValue集成了 Redis 和 Riak,提供多个常用场景下的简单封装,便于构建 key-value 模块。
Spring Data LDAP集成了 Spring Data repository 对 Spring LDAP 的支持。
Spring Data MongoDB集成了对数据库 MongoDB 支持。
Spring Data Redis集成了对 Redis 的支持。
Spring Data REST集成了对 RESTful 资源的支持。
Spring Data for Apache Cassandra集成了对大规模、高可用数据源 Apache Cassandra 的支持。
Spring Data for Apace Geode集成了对 Apache Geode 的支持。
Spring Data for Apache Solr集成了对 Apache Solr 的支持。
Spring Data for Pivotal GemFire集成了对 Pivotal GemFire 的支持。

1.2 社区模块

模块名称
作用
Spring Data Aerospike集成了对 Aerospike 的支持
Spring Data ArangoDB集成了对 ArangoDB 的支持。
Spring Data Couchbase集成了对 Couchbase 的支持。
Spring Data Azure Cosmos DB集成了对 Azure Cosmos 的支持。
Spring Data Cloud Datastore集成了对 Google Datastore 的支持
Spring Data Cloud Spanner集成了对 Google Spanner 的支持。
Spring Data DynamoDB集成了对 DynamoDB 的支持。
Spring Data Elasticsearch集成了对搜索引擎框架 Elasticsearch 的支持。
Spring Data Hazelcast集成了对 Hazelcast 的支持。
Spring Data Jest集成了对基于 Jest REST client 的 Elasticsearch 的支持。
Spring Data Neo4j集成了对 Neo4j 数据库的支持。
Spring Data Vault集成了对 Vault 的支持。

2.JPA

JPA(Java Persistence APl)是 Java 的持久化 API,用于对象的持久化。它是一个非常强大的 ORM 持久化的解决方案,免去了使用 JDBCTemplate 开发的编写脚本工作。JPA 通过简单约定好接口方法的规则自动生成相应的 JPQL 语句,然后映射成 POJO 对象。

JPA 是一个规范化接口,封装了 Hibernate 的操作作为默认实现,让用户不通过任何配置即可完成数据库的操作。JPA、Spring Data 和 Hibernate 的关系如下图所示。
在这里插入图片描述
Hibernate 主要通过 hibernate-annotationhibernate-entitymanagerhibernate-core 三个组件来操作数据。

  • hibernate-annotation:是 Hibernate 支持 annotation 方式配置的基础,它包括标准的 JPAannotation、Hibernate 自身特殊功能的 annotation。
  • hibernate-core:是 Hibernate 的核心实现,提供了 Hibernate 所有的核心功能。
  • hibernate-entitymanager:实现了标准的 JPA,它是 hibernate-core 和 JPA 之间的适配器,它不直接提供 ORM 的功能,而是对 hibernate-core 进行封装,使得 Hibernate 符合 JPA 的规范。

如果要 JPA 创建《Java 的数据库连接模板:JDBCTemplate》中 “2.2 新建实体类” 里的实体,可使用以下代码来实现。

@Data
@Entity
public class User {private int id;@Id// id 的自增由数据库自动管理@GeneratedValue(strategy = GenerationType.IDENTITY)private String username;private String password;
}

对比 JPA 与 JDBCTemplate 创建实体的方式可以看出:JPA 的实现方式简单明了,不需要写映射(支持自定义映射),只需要设置好属性即可。id 的自增由数据库自动管理,也可以由程序管理,其他的工作 JPA 自动处理好了。

3.使用 JPA

要使用 JPA,只要加入它的 Starter 依赖,然后配置数据库连接信息。

3.1 添加 JPA 和 MySQL 数据库的依赖

下面以配置 JPA 和 MySQL 数据库的依赖为例,具体配置见以下代码:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

3.2 配置数据库连接信息

Spring Boot 项目使用 MySQL 等关系型数据库,需要配置连接信息,可以在 application.properties 文件中进行配置。以下代码配置了与 MySQL 数据库的连接信息:

spring.datasource.url=jdbc:mysql://127.0.0.1/book?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql= true
  • spring.datasource.username:要填写的数据库用户名。
  • spring.datasource.password:要填写的数据库密码。
  • spring.jpa.show-sql:开发工具的控制台是否显示 SQL语句,建议打开。
  • spring.jpa.properties.hibernate.hbm2ddl.auto:hibernate 的配置属性,其主要作用是自动创建、更新、验证数据库表结构。该参数的几种配置如下表所示。
属性
说明
create每次加载 Hibernate 时都会删除上一次生成的表,然后根据 Model 类再重新生成新表,哪怕没有任何改变也会这样执行,这会导致数据库数据的丢失。
create-drop每次加载 Hibernate 时会根据 Model 类生成表,但是 sessionFactory 一旦关闭,表就会自动被删除。
update最常用的属性。第一次加载 Hibernate 时会根据 Model 类自动建立表的结构(前提是先建立好数据库)。以后加载 Hibernate 时,会根据 Model 类自动更新表结构,即使表结构改变了,但表中的数据仍然存在,不会被删除。要注意的是,当部署到服务器后,表结构是不会被马上建立起来的,要等应用程序第一次运行起来后才会建立。Update 表示如果 Entity 实体的字段发生了变化,那么直接在数据库中进行更新。
validate每次加载 Hibernate 时,会验证数据库的表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

4.了解 JPA 注解和属性

4.1 常用注解

注解
说明
@Entity声明类为实体
@Table声明表名,@Entity 和 @Table 注解一般一块使用,如果表名和实体类名相同,那么 @Table 可以省略
@Basic指定非约束明确的各个字段
@Embedded用于注释属性,表示该属性的类是嵌入类(@embeddable 用于注释 Java 类的,表示类是嵌入类)
@Id指定的类的属性,一个表中的主键
@GeneratedValue指定如何标识属性可以被初始化,如 @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="repair_seq"),表示主键生成策略是 sequence,还有 Auto、Identity、Native 等
@Transient表示该属性并非一个数据库表的字段的映射,ORM 框架将忽略该属性。如果一个属性并非数据库表的字段映射,就务必将其标示为 @Transient,即它是不持久的,为虚拟字段
@Column指定持久属性,即字段名。如果字段名与列名相同,则可以省略。使用方法,如 @Column(length=11, name="phone", nullable=false, columnDefinition="varchar(11) unique comment '电话号码'")
@SequenceGenerator指定在 @GeneratedValue 注解中指定的属性的值。它创建一个序列
@TableGenerator在数据库生成一张表来管理主键生成策略
@AccessType这种类型的注释用于设置访问类型。如果设置 @AccessType(FIELD),则可以直接访问变量,并且不需要使用 Getter 和 Setter 方法,但必须为 public 属性。如果设置 @AccessType(PROPERTY),则通过 Getter 和 Setter 方法访问 Entity 的变量
@UniqueConstraint指定的字段和用于主要或辅助表的唯一约束
@ColumnResult可以参考使用 select 子句的 SQL 查询中的列名
@NamedQueries指定命名查询的列表
@NamedQuery指定使用静态名称的查询
@Basic指定实体属性的加载方式,如 @Basic(fetch=FetchType.LAZY)
@Jsonignore作用是 JSON 序列化时将 Java Bean 中的一些属性忽略掉,序列化和反序列化都受影响

4.2 映射关系的注解

注解
说明
@JoinColumn指定一个实体组织或实体集合。用在 多对一一对多 的关联中
@OneToOne定义表之间 一对一 的关系
@OneToMany定义表之间 一对多 的关系
@ManyToOne定义表之间 多对一 的关系
@ManyToMany定义表之间 多对多 的关系

4.3 映射关系的属性

属性名
说明
targetEntity表示默认关联的实体类型,默认为当前标注的实体类。
cascade表示与此实体一对一关联的实体的级联样式类型,以及当对实体进行操作时的策略。在定义关系时经常会涉及是否定义 Cascade(级联处理)属性,如果担心级联处理容易造成负面影响,则可以不定义。它的类型包括 CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、CascadeType.MERGE(级联更新)、CascadeType.ALL(级联新建、更新、删除、刷新)。
fetch该实体的加载方式,包含 LAZY 和 EAGER。
optional表示关联的实体是否能够存在 null 值。默认为 true,表示可以存在 null 值。如果为 false,则要同时配合使用 @JoinColumn 标记。
mappedBy双向关联实体时使用,标注在不保存关系的实体中。
JoinColumn关联指定列。该属性值可接收多个 @JoinColumn。用于配置连接表中外键列的信息。@JoinColumn 配置的外键列参照当前实体对应表的主键列。
JoinTable两张表通过中间的关联表建立联系时使用,即多对多关系。
PrimaryKeyJoinColumn主键关联。在关联的两个实体中直接使用注解 @PrimaryKeyJoinColumn 注释。

懒加载 LAZY 和实时加载 EAGER 的目的是,实现关联数据的选择性加载。

  • 懒加载 是一种延迟加载策略,即在真正需要访问对象的属性时,才从数据库中加载数据。当 Hibernate 在查询数据库时遇到关联对象(如一对多、多对一、多对多等关系),并不会立即加载关联对象的数据,而只会加载主键 ID。只有当程序真正需要访问关联对象的属性时,Hibernate 才会发出 SQL 语句去加载数据。这种策略的优点在于,如果程序并不需要访问关联对象的所有属性,那么就可以节省数据库访问的开销,提高程序性能。但是,如果在使用懒加载的对象后关闭了 Session,那么在访问其关联对象的属性时,就会抛出 LazyInitializationException 异常,因为 Hibernate 需要在 Session 的作用范围内才能发出 SQL 语句加载数据。
  • 实时加载 是一种积极加载策略,即在加载一个对象时,会立即加载与其关联的所有对象。当 Hibernate 在查询数据库时遇到关联对象,会立即发出 SQL 语句加载关联对象的数据,并将其全部加载到内存中。这种策略的优点在于,程序可以随时访问关联对象的属性,而无需担心 Session 是否已经关闭。但是,如果关联对象的数据量很大,那么就会消耗大量的内存,并可能导致性能下降。

在 Spring Data JPA 中,要控制 Session 的生命周期,否则会出现 could not initialize proxy [xxxx#18] - no Session 错误。可以在配置文件中配置以下代码来控制 Session 的生命周期:

spring.jpa.open-in-view=true
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

5.用 JPA 构建实体数据表

下面通过实例来体验如何通过 JPA 构建对象/关系映射的实体模型。

package com.example.demo.entity;import lombok.Data;import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;@Entity
@Data
public class Article implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private long id;@Column(nullable = false, unique = true)@NotEmpty(message = "标题不能为空")private String title;@Column(columnDefinition = "enum('图','图文','文')")private String type;private Boolean available = Boolean.FALSE;@Size(min = 0, max = 20)private String keyword;@Size(max = 255)private String description;@Column(nullable = false)private String body;@Transientprivate List keywordlists;public List getKeywordlists() {return Arrays.asList(this.keyword.trim().split("|"));}public void setKeywordlists(List keywordlists) {this.keywordlists = keywordlists;}
}

如果想创建虚拟字段,则通过在属性上加注解 @Transient 来解决。

运行项目后会自动生成数据表。完成后的数据表如下图所示。

在这里插入图片描述

相关文章:

  • 数据结构-第七章(B树和B+树)
  • 每日一道算法题 判断子序列
  • linux 环境报错:Peer reports incompatible or unsupported protocol version
  • sheng的学习笔记-hadoop,MapReduce,yarn,hdfs框架原理
  • 不使用AMap.DistrictSearch,通过poi数据绘制省市县区块
  • 巴西市场有哪些电商平台?巴西最畅销的产品有哪些?
  • 揭秘,PyArmor库让你的Python代码更安全
  • Linux 程序打包
  • 时尚品牌GOODBAI好人好事系列纪录片——Jupiter乐队的热血与梦想
  • ubuntu 18 虚拟机安装(3)安装mysql
  • Hadoop3:参数调优-核心参数NameNode内存配置、并发数配置、回收站配置
  • JAVA学习-练习试用Java实现“天际线问题”
  • Linux Ubuntu 20.04.06 安装Onboard虚拟键盘教程
  • gitignore
  • JAVA学习笔记-JAVA基础语法-DAY20-字节流、字符流
  • CAP理论的例子讲解
  • Create React App 使用
  • crontab执行失败的多种原因
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • Javascript设计模式学习之Observer(观察者)模式
  • jQuery(一)
  • Linux CTF 逆向入门
  • Nacos系列:Nacos的Java SDK使用
  • PaddlePaddle-GitHub的正确打开姿势
  • python学习笔记 - ThreadLocal
  • QQ浏览器x5内核的兼容性问题
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • vue数据传递--我有特殊的实现技巧
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 分布式事物理论与实践
  • 如何在GitHub上创建个人博客
  • 微服务框架lagom
  • 问题之ssh中Host key verification failed的解决
  • 7行Python代码的人脸识别
  • C# - 为值类型重定义相等性
  • postgresql行列转换函数
  • 关于Android全面屏虚拟导航栏的适配总结
  • 数据库巡检项
  • #前后端分离# 头条发布系统
  • (1)bark-ml
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (Java)【深基9.例1】选举学生会
  • (poj1.2.1)1970(筛选法模拟)
  • (pojstep1.1.2)2654(直叙式模拟)
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET下的多线程编程—1-线程机制概述
  • .NET正则基础之——正则委托
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • .vimrc 配置项
  • 。Net下Windows服务程序开发疑惑