认识 JPA

JPA-Java Persistence API,即Java持久化API,总得来说,JPA 为对象关系映射提供了⼀种基于 POJO 的持久化模型

  • 简化数据持久化代码的开发⼯作
  • 为 Java 社区屏蔽不同持久化 API 的差异

而我们常说的Hibernate又是什么呢?它其实是JPA的一种实现

认识 Spring Data

以前,Spring只是在内部实现了支持JDBC、JPA等的方式。后来,Spring将所有对于数据操作的工具都整理在了Spring Data中,Spring Data 在保留底层存储属性的同时,提供相对一致的、基于Spring的编程模型。
主要模块:

Spring Data JPA

Spring Data JDBC

Spring Data Redis

Spring Data MongoDB

认识 Spring Data JPA

Spring Data JPA,即Spring对JPA的封装。

官网上讲:Spring Data JPA旨在通过将工作量减少到实际需要的数量,来显著改善数据访问层的操作作为开发人员,你只需要写你的repository接口,包括自定义的方法,Spring会自动提供实现

常用的jpa实体类注解

通过JPA提供的一些实体类注解,我们可以配置一个对应的表,从而在程序运行时,JPA可以自动实现为我们建表的工作,常见的JPA实体类注解如下:

实体

  • @Entity @MappedSuperclass
  • @Table(name)
  • @Entity与@MappedSuperclass都是声明实体类的注解

@Entity表示所声明的实体类里面定义的所有属性,均与对应的表关联@MappedSuperclass表示所注解的类为一个父类,子类可以通过继承该父类来扩展自己的属性@Table(name),表明该实体类与数据库中的某个表关联

主键 • @Id• @GeneratedValue(strategy, generator)• @SequenceGenerator(name, sequenceName)

@Id和@GeneratedValue常常组合起来,用于主键声明,并指定主键生成策略和生成器(若不指定,JPA会根据所引入驱动依赖的数据库进行默认策略的设置)@SequenceGenerator注解,表示主键会采用序列号的方式生成

映射

•@Column(name,nullable,length,insertable,updatable)

•@JoinTable(name) @JoinColumn(name)

均用在属性上。@Column指定一个属性所映射的字段信息
若存在外键,可以使用@JoinTable(name) @JoinColumn(name)组合进行定义

关系

  • OneToOne
  • OneToMany
  • ManyToOne
  • ManyToMany
  • OrderBy

前四个注解用在属性上,分别表示表与该属性的对应关系

@OrderBy同样使用在属性上,表示@oneToMany以及@ManyToMany,即一对多或者多对多时,字段的排序方式

Repository介绍

加上@EnableJpaRepositories,即可开启JPA的repository的支持,Spring 就会发现以下repository的扩展
CrudRepository 提供基本增删改查方法
PagingAndSortingRepository 用于分页、排序方法
JpaRepository 用于持久化等方法

查询方式

1 ) 根据方法名定义查询
查询方法,默认只提供了查询所有或者按照ID查询的方法。
若想要查询更丰富的内容,比如按照某个条件查询、统计记录数、排序展示、多条件查询、查询第一条或最后一条等,这么多复杂的场景,依旧不需要写sql,我们只需要在repository中定义如下格式的方法就可以轻而易举的实现啦

• find…By… / read…By… / query…By… / get…By…• count…By…• …OrderBy…[Asc / Desc]• And / Or / IgnoreCase• Top / First / Distinct

2) 分页查询
• PagingAndSortingRepository
• Pageable / Sort
• Slice / Page
要想实现分页查询,可以使用PagingAndSortingRepository接口,与Pagable/Sort类相配合,即可实现分页查询

实战环节
对原理有个大概的了解,接下来,就进入今天的实战环节啦,本次实战依旧演示操作mysql数据库

01. 引入依赖

只需要引入spring-data-jpa和mysql驱动两个主要依赖。

org.springframework.boot    spring-boot-starter-data-jpamysql    mysql-connector-java    runtime

02. 属性配置

分别进行数据库连接信息以及jpa的相关信息配置
以下分别为大家演示了jpa的建表机制是否打印sql语句以及是否格式化sql语句显示这3个常用的配置项

• find…By… / read…By… / query…By… / get…By…• count…By…• …OrderBy…[Asc / Desc]• And / Or / IgnoreCase• Top / First / Distinct

其中,JPA的建表机制分为四种,注释中已标出,大家可以按照实际需求,选择不同机制,一般情况建议选择update机制,比较完善,也不用怕每次清空了表或者数据

03. 创建实体类

根据我们在战前准备中所介绍的实体类的注解,我们建立好的实体类User如下:

@Entity@Table(name = "USER")@Builder@Data@NoArgsConstructor@AllArgsConstructorpublic class User implements Serializable {    @Id    @GeneratedValue    private Long id;    private String name;    @Column(updatable = false)    @CreationTimestamp    private Date createTime;    @UpdateTimestamp    private Date updateTime;}

首先使用@Entity与@Table(name="USER")组合,表明该实体类与数据库中的user表关联

@Id与@GeneratedValue组合,表明字段id被映射为主键,JPA会根据引入的数据库依赖,来配置对应的主键生成策略

而属性createTime,分别使用注解@Column(updatable=false)和@CreationTimestamp表示它不可被修改,且对应表中字段的值默认为插入对应记录的时间

注解@UpdateTimestamp则表示,属性updateTime会自动变为对应行记录的更新时间

04. 创建repository

创建自己的UserRepository接口,并实现CrudRepository

#1、数据库连接信息配置spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8spring.datasource.username=rootspring.datasource.password=123456#可以不用配置数据库驱动,SpringBoot 会根据引入的依赖进行自动配置#spring.datasource.driver-class-name=com.mysql.jdbc.Driver#2、jpa配置信息#建表机制#create-drop - 运行程序新建,程序结束:删表#create -运行程序会新建表,程序结束:表的数据会清空#update - 没有表格时会新建表格,表内有数据不会清空,只会更新,#valid - 运行程序会校验数据与数据库的字段类型是否相同,不同会报错spring.jpa.hibernate.ddl-auto=update#打印sql开关spring.jpa.properties.hibernate.show_sql=true#是否格式化sqlspring.jpa.properties.hibernate.format_sql=true

05. 调用repository方法

1)开启jpa的repossitory注解
在启动类上添加注解:@EnableJpaRepositories2)注入自定义的Repository
3) 调用具体数据库操作方法

@SpringBootApplication@Slf4j@EnableJpaRepositoriespublic class SpringBootJpaApplication implements ApplicationRunner {    @Autowired    private UserRepository userRepository;    @Override    public void run(ApplicationArguments args) throws Exception {        User user = User.builder()                .name("小米")                .createTime(new Date())                .updateTime(new Date())                .build();        userRepository.save(user);        log.info("one user added :{}",user);        Iterable users = userRepository.findAll();        users.forEach(System.out::println);    }

06. 运行项目

通过运行项目,我们可以通过打印出的sql语句看到,JPA在服务启动时,分别为我们创建了对应于实体类User的user表,并生成了序列化主键id


java jpa引进来了为什么还报红_实体类


接着执行了数据库的插入操作,成功插入一条数据


java jpa引进来了为什么还报红_spring_02


最后,执行数据库的查询语句,查询出我们所添加的一条user记录


java jpa引进来了为什么还报红_实体类_03


回顾一下,我们的主要的操作其实就只是实现了@CrudRepository接口,然后直接调用其方法,就可以操作数据库了
那么,简单的数据库操作就实现啦~


庆祝一会儿,然后开始接下来的进阶操作,我们试着自定义一个查询方法根据姓名查询,并以CreateTime降序排序的方法:,findByNameOrderByCreateTimeDesc(String name),调用,并运行服务之后,结果如下:


java jpa引进来了为什么还报红_JPA_04


打印出的sql语句表示:根据姓名查询,并以CreateTime降序排序
相应地,如果要定义其他查询方法,只需要直接在自定义的Repository中直接按照第一节中的方法定义规则进行定义即可,具体规则可以查看包org.springframework.data.repository.query.parser中的各类,比如PartTree类:


java jpa引进来了为什么还报红_java jpa引进来了为什么还报红_05


Tips:JPA也有专门的@Query注解以及JPA Named Queries,可以分别在方法上或者xml文件中自定义sql,实现更多操作场景,感兴趣的话,大家可以参考官网查看哦~

三 总结

相对于Mybatis来说,我们可以看到,JPA不知方便多少倍了。它可以说是真正意义上的ORM框架,有以下两大优势:

I.直接可以通过实体类与表、实体属性与表的字段之间的关联,自动为我们建表II.使用时不需要再考虑使用的是何种数据库,也基本不需要写sql语句



但是呢,正如我们所看到的那样,正因为JPA将ORM封装的太完善了,使得我们操作数据库的灵活性大大降低了。比如我们如果想要实现多表关联的查询、多条件查询等等,都会变得更加复杂

所以,项目中要想使用JPA,一定得预先根据项目实际需求,来权衡这些特点,恭喜你,又get到了几个技能点:

1、JPA、Spring DATA的定位与功能
2、Spring DATA JPA操作数据库的方式
3、JPA让人又爱又恨的原因

嗯,就这样。每天学习一点,时间会见证你的成长,下期预告:Spring Boot(五):重新学习Mybatis

本期项目代码已上传到github~有需要的可以参考

https://github.com/wangjie0919/Spring-Boot-Notes