SpringData - JPA

生命不息,写作不止

继续踏上学习之路,学之分享笔记

总有一天我也能像各位大佬一样

一个有梦有戏的人 @怒放吧德德

分享学习心得,欢迎指正,大家一起学习成长!

JPA简介

JPA 即Java Persistence API。是一款持久层框架,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。JPA的对象关系映射(ORM)模型是基于Hibernate。是一款面向对象的ORM框架,JPA不需要关心数据库字段,通过注解将数据库表与实体完成映射,在java中的操作只需要对实体进行操作即可。

什么是ORM?

ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射。也就是说ORM是建立了一个实体与数据库表的关系,使得开发者对实体的直接操作而不是对数据库的操作,但操作实体也就等同于操作了数据库。

ORM框架还有:MyBatis、Hibernate

SpringData-JPA

Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。

它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!

Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现

在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦。

SpringBoot整合JPA

接下来通过一个案例简单学习一下JPA,并且在案例中学习一些相关知识。

导入依赖

需要导入jpa坐标和mysql依赖包

  1. <dependencies>
  2. <!--jpa-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-data-jpa</artifactId>
  6. </dependency>
  7. <!--Mysql依赖包-->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <scope>runtime</scope>
  12. </dependency>
  13. </dependencies>

编写配置文件

先配置数据源,采用mysql8.0。还包括配置jpa的相关配置。主要是配置jpa的sql日志打印和自动创建表格。

  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.cj.jdbc.Driver
  4. url: jdbc:mysql://localhost:3306/springboot_demo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  5. username: root
  6. password: 12356
  7. jpa:
  8. show-sql: true
  9. hibernate:
  10. ddl-auto: create # 自动创建表格,之后改成update

jpa的底层是通过hibernate执行的,通过配置ddl-auto能够自动创建表,但是这个不建议使用,如果是create,在项目运行的时候就会把存在的表删除在添加。详情如下:

ddl-auto属性用于设置自动表定义,可以实现自动在数据库中为我们创建一个表,表的结构会根据我们定义的实体类决定,它有4种

  • create 启动时删数据库中的表,然后创建,退出时不删除数据表
  • create-drop 启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错
  • update 如果启动时表格式不一致则更新表,原有数据保留
  • validate 项目启动表结构进行校验 如果不一致则报错

接下来就可以开始体验jpa了

创建实体类

可见通过注解可以实现实体与数据库的直接映射,jpa操作的就是这些实体就等同操作数据库的表结构。

  1. package com.jpa.demo.domain;
  2. import lombok.Data;
  3. import javax.annotation.Generated;
  4. import javax.persistence.*;
  5. import java.io.Serializable;
  6. /**
  7. * @author: lyd
  8. * @description: 实体User
  9. * @Date: 2022/10/2
  10. */
  11. @Data
  12. @Entity
  13. @Table(name = "sys_user")
  14. public class User implements Serializable {
  15. @Id
  16. @Column(name = "user_id")
  17. @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增
  18. private Long id;
  19. private String username;
  20. private String nickName;
  21. private String password;
  22. }
  • @Data:lombok下的注解,主要是方便开发,减少对get、set、tostring的编写。这个需要导入相应的依赖坐标。
  • @Entity:声明是一个实体。
  • @Table(name = "sys_user"):指明数据库中表的名字实现实体与数据表映射。
  • @Id:声明主键。
  • @Column(name = "user_id"):指明是表中的哪个字段。
  • @GeneratedValue(strategy = GenerationType.IDENTITY): GenerationType.IDENTITY:实现自增

启动项目

当我们启动项目的时候,数据库会自动创建表结构。

看一下数据库,发现表已经自动创建

对表操作

增加数据

首先需要创建UserRepository接口,要通过继承JpaRepository<T, ID>,提供实体类和id的类型。

  1. /**
  2. * @author: lyd
  3. * @description: UserRepository
  4. * @Date: 2022/10/2
  5. */
  6. @Repository
  7. public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
  8. }

编写测试类

通过调用save方法即可完成保存操作

  1. package com.jpa.demo.test;
  2. import com.jpa.demo.domain.User;
  3. import com.jpa.demo.repository.UserRepository;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.boot.test.context.SpringBootTest;
  6. import org.junit.jupiter.api.Test;
  7. /**
  8. * @author: lyd
  9. * @description: 测试类
  10. * @Date: 2022/10/2
  11. */
  12. @SpringBootTest
  13. public class JpaTest {
  14. @Autowired
  15. private UserRepository userRepository;
  16. @Test
  17. void InsertTest() {
  18. User user = new User();
  19. user.setNickName("怒放吧德德");
  20. user.setUsername("lyd_code");
  21. user.setPassword("lyd_open");
  22. User save = userRepository.save(user);
  23. System.out.println(save);
  24. }
  25. }

运行结果

查看数据

通过findAll就可以直接获取得到所有的数据。

  1. @Test
  2. void QueryTest() {
  3. List<User> all = userRepository.findAll();
  4. all.forEach(System.out::println);
  5. }

就能在控制台中看到:

分页查找

jpa也是实现了分页操作的方法。通过PageRequest.of(0,1)可以完成分页。

  1. @Test
  2. void PageRequestTest() {
  3. userRepository.findAll(PageRequest.of(0,1)).forEach(System.out::println);
  4. }

其底层对数据库的操作就会加上limit.

根据ID查找

返回是Optional类,User类型的数组

  1. @Test
  2. void FindByIdTest() {
  3. Optional<User> user = userRepository.findById(1L);
  4. System.out.println(user);
  5. }

Java8 新特性Optional类

Optional 类新特性

Optional 类是一个可以为null的容器对象

如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象

Optional 是个容器:它可以保存类型T的值,或仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测

Optional 类的引入很好的解决空指针异常

方法命名规则自定义查询

方法命名规则查询就是根据方法的名字,就能创建查询。需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询。通过jpa的规则要求来实现自己命名查询。

按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。

编写Repository

根据一定的规则来编写方法命名。jpa会自动识别方法名称进行操作。

  1. package com.jpa.demo.repository;
  2. import com.jpa.demo.domain.User;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  5. import org.springframework.stereotype.Repository;
  6. import java.util.List;
  7. /**
  8. * @author: lyd
  9. * @description: UserRepository
  10. * @Date: 2022/10/2
  11. */
  12. @Repository
  13. public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
  14. //根据nickname查询
  15. List<User> findAllByNickName(String str);
  16. }

通过测试可以看到如下结果:

在编写repository的时候会有一些规则提示,也就是只有符合这些规则才能够被识别。这里只是展现了findxxx,实际上还有许多。

具体的关键字,使用方法和生产成SQL如下表所示

使用JPQL的方式查询(注解式SQL)

通过Query注解可以实现更多灵活的条件查询等SQL·操作。@Query 注解的使用非常简单,只需在方法上面标注该注解,同时提供一个JPQL查询语句即可,并且,在这些SQL语句中都是使用实体来进行操作,并非数据库的表结构来操作。

计数

通过Query可以写自己的SQL语句

  1. @Query("select count(u) from User u") // 这里使用的是实体,并不是数据库的表名和字段
  2. Integer countUser();

测试

  1. @Test
  2. void CountUser() {
  3. Integer integer = userRepository.countUser();
  4. System.out.println(integer);
  5. }

结果

参数传递

在通过注解写SQL的时候,也需要是携带参数的,而Query通过?占位符来获得传来的参数数据,通过参数的位置定位哪个参数。

  1. //修改数据 一定加上@Modifying 注解
  2. @Transactional
  3. @Modifying
  4. @Query("update User set username=?1 where id=?2")
  5. int updateUsernameByIds(String username,Long id);

结果

也可以使用原生的SQL,只需要加上 nativeQuery = true 即可。

实体关系对应

jpa中实体包括一对一,一对多,多对多,多对一关系,并且提供了相应的注解。接下来通过案例来实现关系。

一对一

首先创建部门表,使用户指向一个部门。

  1. package com.jpa.demo.domain;
  2. import lombok.Data;
  3. import javax.persistence.*;
  4. import java.io.Serializable;
  5. /**
  6. * @author: lyd
  7. * @description: 部门
  8. * @Date: 2022/10/2
  9. */
  10. @Entity
  11. @Data
  12. @Table(name="sys_dept")
  13. public class Dept implements Serializable {
  14. @Id
  15. @Column(name = "dept_id")
  16. @GeneratedValue(strategy = GenerationType.IDENTITY)
  17. private Long id;
  18. private String name;
  19. }

在User实体中加字段,通过OneToOne注解完成。

  1. @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) //设置关联操作为ALL
  2. @JoinColumn(name = "dept_id")
  3. private Dept dept;

这里的关联级别也是有多个,一般设置为all就行

  • ALL:所有操作都进行关联操作
  • PERSIST:插入操作时才进行关联操作
  • REMOVE:删除操作时才进行关联操作
  • MERGE:修改操作时才进行关联操作

    这样就可以编写测试
  1. @Test
  2. void OneToOneTest() {
  3. User user = new User();
  4. user.setNickName("爱国德德");
  5. user.setUsername("lyd_code_studio");
  6. user.setPassword("lyd_open");
  7. Dept dept = new Dept();
  8. dept.setName("研发部");
  9. user.setDept(dept);
  10. User save = userRepository.save(user);
  11. System.out.println(save);
  12. }

通过测试可得数据库结果,





通过关联,会在两个表中进行插入,删除也是会删除两个表中数据。

一对多

  1. @OneToMany:
  2. 作用:建立一对多的关系映射
  3. 属性:
  4. targetEntityClass:指定多的多方的类的字节码
  5. mappedBy:指定从表实体类中引用主表对象的名称。
  6. cascade:指定要使用的级联操作
  7. fetch:指定是否采用延迟加载
  8. orphanRemoval:是否使用孤儿删除

创建一个文章表来实现一对多关系,一个用户可以发表多个文章,一个文章只属于一个用户,因此在用户表中是一对多,在文章表就是多对一。

通过@ManyToOne注解完成关系

  1. package com.jpa.demo.domain;
  2. import lombok.Data;
  3. import javax.persistence.*;
  4. /**
  5. * @author: lyd
  6. * @description: 文章表
  7. * @Date: 2022/10/2
  8. */
  9. @Data
  10. @Entity
  11. @Table(name="yun_article")
  12. public class Article {
  13. @Id
  14. @Column(name = "article_id")
  15. @GeneratedValue(strategy = GenerationType.IDENTITY)
  16. private Long id;
  17. @Column(nullable = false, length = 50) // 映射为字段,值不能为空
  18. private String title;
  19. @Basic(fetch = FetchType.LAZY) // 懒加载
  20. @Column(nullable = false) // 映射为字段,值不能为空
  21. private String content;
  22. @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false)//可选属性optional=false,表示user不能为空。删除文章,不影响用户
  23. @JoinColumn(name="user_id")//设置在article表中的关联字段(外键)
  24. private User user;
  25. }

在user实体这边就是一对多关系,并且通过注解完成。

  1. @OneToMany(mappedBy = "user",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
  2. //级联保存、更新、删除、刷新;延迟加载。当删除用户,会级联删除该用户的所有文章
  3. //拥有mappedBy注解的实体类为关系被维护端
  4. private Set<Article> articles;

测试,需要创建ArticleRepository

  1. @Test
  2. void OneToMany() {
  3. User user = userRepository.getById(1L);
  4. Article article1=new Article();
  5. article1.setTitle("如何写好博客");
  6. article1.setContent("如何写好博客");
  7. article1.setUser(user);
  8. articleRepository.save(article1);
  9. Article article2=new Article();
  10. article2.setTitle("如何更进一步学习");
  11. article2.setContent("不断地卷");
  12. article2.setUser(user);
  13. articleRepository.save(article2);
  14. }

运行结果

数据库中

多对多

JPA中使用@ManyToMany来注解多对多的关系,由一个关联表来维护。这个关联表的表名默认是:主表名+下划线+从表名。(主表是指关系维护端对应的表,从表指关系被维护端对应的表)。这个关联表只有两个外键字段,分别指向主表ID和从表ID。字段的名称默认为:主表名+下划线+主表中的主键列名,从表名+下划线+从表中的主键列名。通过@JoinTable来实现中间表。

创建角色表

  1. package com.jpa.demo.domain;
  2. import lombok.Data;
  3. import javax.persistence.*;
  4. import java.io.Serializable;
  5. import java.util.Set;
  6. /**
  7. * @author: lyd
  8. * @description: 角色表
  9. * @Date: 2022/10/2
  10. */
  11. @Data
  12. @Entity
  13. @Table(name = "sys_role")
  14. public class Role implements Serializable {
  15. @Id
  16. @Column(name = "role_id")
  17. @GeneratedValue(strategy = GenerationType.IDENTITY)
  18. private Long id;
  19. @ManyToMany(mappedBy = "roles")
  20. private Set<User> users;
  21. private String name;
  22. @Column(name = "level")
  23. private Integer level = 3;
  24. private String description;
  25. }

在用户表中

  1. @ManyToMany
  2. @JoinTable(name = "sys_users_roles",
  3. joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")},
  4. inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")})
  5. private Set<Role> roles;

测试

  1. @Test
  2. void ManyToMany() {
  3. Role role = new Role();
  4. role.setName("USER");
  5. role.setLevel(2);
  6. role.setDescription("管理员");
  7. roleRepository.save(role);
  8. Set<Role> roles = new HashSet<>();
  9. roles.add(role);
  10. User user = new User();
  11. user.setPassword("lyd_code");
  12. user.setNickName("怒放德德");
  13. user.setUsername("lyd_code");
  14. user.setRoles(roles);
  15. User save = userRepository.save(user);
  16. System.out.println(save);
  17. }

在数据库中的中间表就能够看到如下数据。

文章推荐

创作不易,如有错误请指正,感谢观看!记得点赞哦!

【持久层框架】- SpringData - JPA的更多相关文章

  1. spring boot整合双持久层框架jpa、mybatis

    公司之前用的是spring boot + jpa,但由于jpa无法完美的解决某些动态查询问题,就使用的jdbcTemplate 动态封装SQL,由于代码相对复杂,可读性差,现准备再引入mybatis. ...

  2. 持久层框架JPA与Mybatis该如何选型

    一.现状描述 目前java 持久层ORM框架应用最广泛的就是JPA和Mybatis.JPA只是一个ORM框架的规范, 对该规范的实现比较完整就是Spring Data JPA(底层基于Hibernat ...

  3. 八:SpringBoot-集成JPA持久层框架,简化数据库操作

    SpringBoot-集成JPA持久层框架,简化数据库操作 1.JPA框架简介 1.1 JPA与Hibernate的关系: 2.SpringBoot整合JPA Spring Data JPA概述: S ...

  4. MyBatis持久层框架学习之01 MyBatis的起源和发展

    一.MyBatis的简介  MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.    MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集. MyB ...

  5. Springboot + 持久层框架JOOQ

    简介 官网链接 JOOQ是一套持久层框架,主要特点是: 逆向工程,自动根据数据库结构生成对应的类 流式的API,像写SQL一样 提供类型安全的SQL查询,JOOQ的主要优势,可以帮助我们在写SQL时就 ...

  6. MyBatis持久层框架使用总结

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis . 2 ...

  7. java持久层框架mybatis如何防止sql注入

    看到一篇很好的文章:http://www.jfox.info/ava-persistence-framework-mybatis-how-to-prevent-sql-injection sql注入大 ...

  8. .NET平台下,关于数据持久层框架

    在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: 1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS ...

  9. 菜鸟学习Hibernate——持久层框架

    一.Java操作数据库的阶段. Java对数据库进行操作经历了三个阶段. 1.1操作JDBC阶段 这个阶段就是利用JDBC类来操作数据库.这个阶段出现了两个问题: 代码过度重复:在每一次数据库操作的是 ...

随机推荐

  1. [BJDCTF2020]EasySearch-1

    1.打开之后界面如下: 2.在首界面审查源代码.抓包未获取到有效信息,就开始进行目录扫描,获取到index.php.swp文件,结果如下: 3.访问index.php.swp文件获取源代码信息,结果如 ...

  2. gdb调试器在windows下的相关内容

    1.gdb调试器在visual studio或dev c++中也有类似的调试图形化可视界面,但是gdb不同的是它是由命令行组成,他的界面对于习惯图形化可视界面的用户来说一时间会不知所措 2.通过gcc ...

  3. Command 'ifconfig' not found, but can be installed with: sudo apt install net-tools解决方法

    VMware下安装的Ubuntu 当使用ifconfig命令查看网卡配置信息的时候出错 尝试了很多方法都解决不了,直到输入了下面的内容: 然后自己就更新了很多东西 之后重新输入ifconfig命令就能 ...

  4. 浅谈hooks——useEffect

    react 16.8发布以来,函数式写法逐渐取代class的写法,在react函数式写法中,最重要是就是react所推出的新特性:hook,今天就来简单谈谈最基础的hook--useEffect 在r ...

  5. LyScript 实现对内存堆栈扫描

    LyScript插件中提供了三种基本的堆栈操作方法,其中push_stack用于入栈,pop_stack用于出栈,而最有用的是peek_stack函数,该函数可用于检查指定堆栈位置处的内存参数,利用这 ...

  6. 密码学系列之:PEM和PKCS7,PKCS8,PKCS12

    目录 简介 PEM PKCS7 PKCS8 PKCS12 总结 简介 PEM是一种常见的保存key或者证书的格式,PEM格式的文件一般来说后缀是以.pem结尾的.那么PEM到底是什么呢?它和常用的证书 ...

  7. web前端要学些什么,学习思路

    有没有Web前端大神给个意见 我已学了 html  css JS 马上要学Vue或React不知道那个好 需不需要先了解一下jQuery 还需要学些什么

  8. 喜讯:“行走的文档” 当选 Apache DolphinScheduler Committer啦

    点击上方蓝字关注 Apache DolphinScheduler Apache DolphinScheduler(incubating),简称"DS", 中文名 "海豚调 ...

  9. 关于linux的一点好奇心(四):tail -f文件跟踪实现

    关于文件跟踪,我们有很多的实际场景,比如查看某个系统日志的输出,当有变化时立即体现,以便进行问题排查:比如查看文件结尾的内容是啥,总之是刚需了. 1. 自己实现的文件跟踪 我们平时做功能开发时,也会遇 ...

  10. Excel 插入嵌入式图表和独立图表的方法

    描述 嵌入式图表:是一种与当前工作表相同位置的图表,且悬浮在表格之上,不受表格限制,因此称之为嵌入式图表. 独立图表:是独立于当前工作表的图表,打印时,需要单独将其打印出来. 插入独立图表的图文教程: ...