文章目录
- JPA概述
- JPA
- Spring Data JPA
- JPA注解
- 基础注解
- Entity
- Table
- Id
- Enumerated
- Transient
- Column
- Temporal
- 联合主键注解
- IdClass
- Embeddable和EmbeddedId注解
- 实体之间关联关系注解
- OneToOne
- ManyToOne和OneToMany
- Repository
- JPA查询方式
- DQM(定义查询方法)
- 使用实例
- DMQ方法名中支持的关键字
- 支持分页和排序
- 限制查询结果
- @Query方式查询
- like
- 原生SQL
- 参数
- QueryByExampleExecutor
- 示例
- JpaSpecificationExecutor
- 接口
- Specification接口
- 示例
- img
- open-in-view
JPA概述
1、简介:
Java Persistence API:用于对象持久化的 API。
Java EE 5.0 平台标准的 ORM规范,使得应用程序以统一的方式访问持久层。
2、JPA 是 hibernate 的一个抽象(就像JDBC和JDBC驱动的关系):
JPA 是规范:JPA 本质上就是一种 ORM 规范,不是ORM 框架—— 因为 JPA 并未提供 ORM 实现,它只是制订了一些规范,提供了一些编程的 API 接口,但具体实现则由 ORM 厂商提供实现。
Hibernate是实现:Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现
从功能上来说, JPA 是 Hibernate 功能的一个子集。
3、JPA 的特点:
标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。
简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注释;JPA 的框架和接口也都非常简单。
可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型。
4、JPA 技术:
ORM 映射元数据:JPA 支持 XML 和 JDK 5.0 注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
JPA 的 API:用来操作实体对象,执行CRUD操作,框架在后台完成所有的事情,开发者从繁琐的 JDBC和 SQL代码中解脱出来。
查询语言(JPQL):这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序和具体的 SQL 紧密耦合。
JPA
- 基于ORM思想实现的框架都称为JPA框架
- JPA 是一个基于O/R映射的标准规范,只定义标准规则(如注解、接口),不提供实现。
- JPA 的主要实现有Hibernate、EclipseLink 和OpenJPA 等
Spring Data JPA
对于JPA规范的再次封装,底层实现使用了Hibernate的技术,属于Spring生态的一部分。
JPA注解
基础注解
Entity
- 用于定义这个对象是实体类,将成为JPA的管理对象,必用!
- 只能用在class上,默认值是类名
Table
- 指定数据库的表名,表示此实体对应哪张数据表
- 可以不填,默认表名就是实体名
Id
- 数据库主键,必须有主键
- 可以配合@GeneratedValue定义主键生成策略
Enumerated
- 为实体中的字段提供枚举值
- @Enumerated默认是枚举值所在的下标(不建议用)
- @Enumerated(*.class)表示枚举本身的名称
- @Enumerated(EnumType.ORDINAL)在数据库中存的是0,1
- @Enumerated(EnumType.STRING)在数据库中存的是MIAL/FEMAIL
Transient
- 表示该属性不是一个持久化的属性,不需要映射到数据库中
- 有此注解,JPA持久化的时候会忽略
Column
- 表示该属性对应到数据库中的列名
- 不写的时候直接就是默认字段名
- 默认允许为空
- insertable和updatable可以选择是否在insert或者update是包含此字段
-insertable和updatable一般多用于只读的属性,例如主键和外键等,这些字段的值通常是自动生成的
Temporal
- 表示Date类型的属性映射到对应精度的字段
- @Temporal(TemporalType.Date):只有日期
- @Temporal(TemporalType.Time):只有时间
- @Temporal(TemporalType.TimeStamp):日期+时间
联合主键注解
IdClass
- 新建一个主键类,类中包含主键字段,此类必须实现Serializable接口,无参构造函数必须是默认的,且必须覆盖equals和hashCode方法。equals方法用于判断两个对象是否相同, EntityManger通过find方法来查找Entity时是根据equals的返回值来判断的。 在本例中, 只有对象的值完全相同或同一个对象时才返回true, 否则返回false。 hashCode方法返回当前对象的哈希码, 生成的hashCode相同的概率越小越好, 算法可以进行优化。
- 实体中使用@IdClass(*.class)表示使用此主键类
- 实体中对应的主键字段加上@Id
主键类:主键字段为:title和createUserId联合主键
实体类:
Embeddable和EmbeddedId注解
实体之间关联关系注解
OneToOne
- 表示对象直接一对一的关系,比如一个客户记录表对应一个客户资金表
- 注解放在字段属性上或者放在getter/setter方法上
- 可以配置单向关联和双向关联
- 如果是配置单向关联,则此注解只用在拥有外键的一方
- OrphanRemoval:表示是否删除孤立元素,例如映射关系是一对一,或一对多。加上这个注解,即使不设置级联关系,删除一的时候,多的一方肯定是孤立元素了。
- 尽量不适用一对一中的双向关联
- 级联操作应该保持默认
- 关联的地方尽量使用LAZY
ManyToOne和OneToMany
- ManyToOne表示多对一,用在维护外键关系的一方,我们理解的多的一方
- OneToMoney表示一对多,
- 两个成对使用且维护关系的一方是拥有外键的一方,另一方必须配置apperBy
Repository
Spring Data里面做数据库操作的最底层的抽象接口、 最顶级的父类。
JPA查询方式
DQM(定义查询方法)
- 一种是直接通过方法名实现
- 另一种通过@Query手动在方法上定义
使用实例
DMQ方法名中支持的关键字
支持分页和排序
限制查询结果
@Query方式查询
like
原生SQL
参数
QueryByExampleExecutor
示例
- 查询所有名称是“linan”结尾且公司名称是“海”开始的记录
- 实体对象:在持久化框架中与Table对应的域对象,一个对象代表数据库表中的一条记录,如上例中person对象。在构建查询条件时,一个实体对象代表的是查询条件中的“数值”部分。如:要查询姓“linan”的客户,实体对象只能存储条件值“linan”。
- 匹配器:ExampleMatcher对象,它是匹配“实体对象”的,表示了如何使用“实体对象”中的“值”进行查询,它代表的是“查询方式”,解释了如何去查的问题。
- 实例:即Example对象,代表的是完整的查询条件。由实体对象(查询条件值)和匹配器(查询方式)共同创建。
就是通过一个例子来查询。要查询的是Person对象,查询条件也是一个Person对象,通过一个现有的对象作为例子,查询和这个例子相匹配的对象。
JpaSpecificationExecutor
接口
Specification接口
- Root: 代表了可以查询和操作的实体对象,如果将实体对象比喻成表名,那root里面就是这张表里面的字段,是JPQL的实体字段,通过.get(String var0)来获得操作的字段
- CriteriaQuery<?>: 代表一个specific的顶层查询对象,它包含着查询的各个部分,如: select、form、where、group by、order by 等,它提供了查询var1的的方法,常用的有 where、select、having
- CriteriaBuilder: 用来构建CriteriaQuery的构建器对象,其实就相当于条件或条件组合
使用Specification的要点就是CriteriaBuilder,通过这个对象来创建条件,之后返回一个Predicate对象。这个对象中就有了相应的查询需求,我们同样可以定义多个Specification,之后通过Specifications对象将其连接起来
示例
open-in-view
- 两个属性值:true或者false
- True: 假如我们在Controller调用了两个Service层的事务方法,那么在Controller开始执行的时候创建session,直到两个事务都结束且Controller方法执行完毕才关闭Session。
- False:假如我们在Controller调用了两个Service层的事务方法, 每个事务开始的时候都会创建Session,在每个事务结束之后关闭Session。。可能会引起Lazy异常。