详解 spring data jpa,全方位总结

谈一谈 jpa

什么是 jpa ? jpa 的全称是 Java Persistence API , 中文的字面意思就是 java 的持久层 API , jpa 就是定义了一系列标准,让实体类和数据库中的表建立一个对应的关系,当我们在使用 java 操作实体类的时候能达到操作数据库中表的效果(不用写sql ,就可以达到效果),jpa 的实现思想即是 ORM (Object Relation Mapping),对象关系映射,用于在关系型数据库和业务实体对象之间作一个映射。

jpa 并不是一个框架,是一类框架的总称,持久层框架 Hibernate 是 jpa 的一个具体实现,本文要谈的 spring data jpa 又是在 Hibernate 的基础之上的封装实现。

当我们项目中使用 spring data jpa 的时候,你会发现并没有 sql 语句,其实框架的底层已经帮我们实现了,我们只需要遵守规范使用就可以了,下面会详细谈到 spring data jpa 的各种规范细则。

使用 jpa 是可以解决一些我们写 sql 语句的烦恼,但是搞开发的如果 sql 写不好,还是很头疼的。当然本文并不是捧吹 spring data jpa , 另一个数据库层的框架 mybatis 也是十分优秀的框架,该框架是专注 sql 语句的

spring data jpa常用的 jpa 的配置

下面所有演示的代码均来自我个人 github 的 spring-data-jpa 仓库,仓库地址:spring-data-jpa (https://github.com/kickcodeman/spring-data-jpa.git), 读者可以clone 下来运行本项目,验证下面讲的所有知识点。

下面把spring boot 项目关于 jpa 的常用配置 application.properties 配置如下:

#项目端口的常用配置 server.port=8081  
# 数据库连接的配置 spring.datasource.url=jdbc:mysql:///jpa?useSSL=false spring.datasource.username=root spring.datasource.password=zempty123 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver  
#数据库连接池的配置,hikari 连接池的配置 spring.datasource.hikari.idle-timeout=30000 spring.datasource.hikari.connection-timeout=10000 spring.datasource.hikari.maximum-pool-size=15 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.auto-commit=true   
#通过 jpa 自动生成数据库中的表 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect  

下面重点分析一下 jpa 中的三个配置 : spring.jpa.hibernate.ddl-auto=update 该配置比较常用,当服务首次启动会在数据库中生成相应表,后续启动服务时如果实体类有增加属性会在数据中添加相应字段,原来数据仍在,该配置除了 update ,还有其他配置值:

create :该值慎用,每次重启项目的时候都会删除表结构,重新生成,原来数据会丢失不见。

create-drop :慎用,当项目关闭,数据库中的表会被删掉。 validate : 验证数据库和实体类的属性是否匹配,不匹配将会报错。

综上:个人感觉还是使用 update 较为稳妥。

spring.jpa.show-sql=true 该配置当在执行数据库操作的时候会在控制台打印 sql 语句,方便我们检查排错等。

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 数据库的方言配置。

类映射到数据库表的常用注解分析

spring data jpa 提供了很多注解,下面我们把日常常用注解总结如下:

@Entity 是一个类注解,用来注解该类是一个实体类用来进行和数据库中的表建立关联关系,首次启动项目的时候,默认会在数据中生成一个同实体类相同名字的表(table),也可以通过注解中的 name 属性来修改表(table)名称, 如@Entity(name=“stu”) , 这样数据库中表的名称则是 stu 。 该注解十分重要,如果没有该注解首次启动项目的时候你会发现数据库没有生成对应的表。

@Table 注解也是一个类注解,该注解可以用来修改表的名字,该注解完全可以忽略掉不用,@Entity 注解已具备该注解的功能。

@Id 类的属性注解,该注解表明该属性字段是一个主键,该属性必须具备,不可缺少。

@GeneratedValue 该注解通常和 @Id 主键注解一起使用,用来定义主键的呈现形式,该注解通常有多种使用策略,先总结如下:

  1. @GeneratedValue(strategy= GenerationType.IDENTITY) 该注解由数据库自动生成,主键自增型,在 mysql 数据库中使用最频繁,oracle 不支持。
  2. @GeneratedValue(strategy= GenerationType.AUTO) 主键由程序控制,默认的主键生成策略,oracle 默认是序列化的方式,mysql 默认是主键自增的方式。
  3. @GeneratedValue(strategy= GenerationType.SEQUENCE) 根据底层数据库的序列来生成主键,条件是数据库支持序列,Oracle支持,Mysql不支持。
  4. @GeneratedValue(strategy= GenerationType.TABLE) 使用一个特定的数据库表格来保存主键,较少使用。

以上的主键生成策略当中,在数据库 mysql 当中 IDENTITY 和 AUTO 用的较多,二者当中 IDENTITY 用的多些,以下文章当中演示的 demo 主键均使用 @GeneratedValue(strategy= GenerationType.IDENTITY) 的生成策略。

@Column 是一个类的属性注解,该注解可以定义一个字段映射到数据库属性的具体特征,比如字段长度,映射到数据库时属性的具体名字等。

@Transient 是一个属性注解,该注解标注的字段不会被应射到数据库当中。

以上使用的注解是定义一个实体类的常用注解,通过上述的注解我们就可以通过实体类生成数据库中的表,实体类和表建立一个对应的关系,下面贴出一个实体类的定义 demo :

package com.zempty.springbootjpa.entity;
 import lombok.Getter; 
import lombok.Setter; 
import lombok.experimental.Accessors;  
import javax.persistence.*; 
import java.time.LocalDate; 
import java.time.LocalDateTime; 
import java.time.LocalTime;  
@Setter 
@Getter 
@Accessors(chain = true) 
@Entity(name = "stu") 
//@Table public class Student 
{      
@Id     
@GeneratedValue(strategy= GenerationType.TABLE)     
private long id;      
@Column(length = 100)     
private String name;      
@Transient     
private String test;      
private int age;      
private LocalTime onDuty;      
private LocalDate onPosition;      
private LocalDateTime birthdayTime; 
}  

该实体类中的 @Setter ,@Getter, @Accessors(chain =true) 均是 lombok 的注解,不了解的建议了解一下 lombok。 使用上述实体类的注解,当运行项目的时候就会在数据库中生成一个表名是 stu 的表。

类的继承分析

下面来研究一下类之间存在继承关系的时候,jpa 又是如何处理继承关系的呢?这个是很值得了解清楚的,这个搞明白了我们在使用 spring data jpa 的时候可能会事半功倍。

大致总结继承这块有这样三种情况:

  1. 多类一表:多个类之间的属性相同,唯一的区别就是类型上的差异(类名不同),这个时候我们可以为这个共同属性的类建立一个父类,只让父类应射到数据库。
  2. 多类多表:把多个类之间公有的属性提取出来放在它们公有的父类中,各个类之间可以定义自己特有的属性,子类和父类在数据库中都有相应的表和其对应。
  3. 子类建表:把多个类之间公有的属性提取出来放在它们公有的父类中,各个类之间可以定义自己特有的属性,仅仅子类和数据库中的表建立关联关系,父类中的属性延续到每一个子类中,在数据库中每一个子类对应的表都有父类中定义的属性。

jpa 是如何处理上述的三种情况呢? 通过一个注解:@Inheritance 该注解仅使用在父类当中,该注解有三种策略分别对应上述的三种情况,该部分可以参考本人github 仓库 spring-data-jpa(https://github.com/kickcodeman/spring-data-jpa.git) 测试了解 :

  1. @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 该注解从字面来理解即可大致看出含义,只生成一个 table。现在先给出结论:该注解的使用场景是几个实体类的属性大致相同,没有什么区别,唯一区别的可能也就是类名了,这样的话我们可以考虑使用该注解,使用该注解的话我们多个实体类公用一个table ,该表由父类生成,父类中默认会生成一个 dtype 字段,用来表明该条数据是属于哪一个实体类的数据。详细使用可以参考项目包com.zempty.springbootjpa.entity.inheritance.single_table 中的三个类,A1,B1, Group1 三个类的使用,类中的 Group1 是 A1 和 B1 的父类,A1 和 B1 中通常会使用如下的一个注解: @DiscriminatorValue 该注解只有一个 value 值用来标注在插入数据的时候 dtype 字段的值。在包 com.zempty.springbootjpa. inheritance. controller 中的 SingleController 有几个详细的测试案例,可以运行项目,测试几个接口,查看一下数据库查看使用细则。
  2. **@Inheritance(strategy = InheritanceType.JOINED)**该注解使用后,会生成多张表。现在先给出结论性总结如下:当有一个这样的需求,一些属性是多数类都有的,比如,username,password … ,那么我们可以考虑把共有的属性给提取出来,单独做成一个表,类中特殊属性定义在各自的类中。 详细使用可以参项目包 com.zempty. springbootjpa. entity.inheritance.joined 中的三个类 A2, B2, Group2 ,三个类的使用, Group2 是 A2 和 B2 的父类,该案例将会把三个实体类都生成各自的表,当
  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值