JPA学习总结


一. 背景相关
JDK:1.8
IDE:IntelliJ IDEA
db:MYSQL
Spring Boot 结合 JPA
Spring Boot版本:v2.0.2.RELEASE
使用maven管理jar包


二:POM

 1   <dependencies>
 2         <dependency>
 3             <groupId>org.springframework.boot</groupId>
 4             <artifactId>spring-boot-starter-test</artifactId>
 5             <scope>test</scope>
 6         </dependency>
 7         <!--JPA-->
 8         <dependency>
 9             <groupId>org.springframework.boot</groupId>
10             <artifactId>spring-boot-starter-data-jpa</artifactId>
11         </dependency>
12         <!--热部署-->
13         <dependency>
14             <groupId>org.springframework.boot</groupId>
15             <artifactId>spring-boot-devtools</artifactId>
16             <scope>runtime</scope>
17             <optional>true</optional>
18         </dependency>
19         <!--MySql数据库-->
20         <dependency>
21             <groupId>mysql</groupId>
22             <artifactId>mysql-connector-java</artifactId>
23             <scope>runtime</scope>
24         </dependency>
25         <!--Pageable使用QPageRequest需要这个-->
26         <dependency>
27             <groupId>com.querydsl</groupId>
28             <artifactId>querydsl-jpa</artifactId>
29         </dependency>
30     </dependencies>
31 
32     <build>
33         <plugins>
34             <plugin>
35                 <groupId>org.springframework.boot</groupId>
36                 <artifactId>spring-boot-maven-plugin</artifactId>
37                 <configuration>
38                     <fork>true</fork>
39                 </configuration>
40             </plugin>
41         </plugins>
42     </build>

 



三:材料准备
两张实体表 teacher、studnett

 1 @Entity
 2 @Table(name = "student")
 3 public class Student {
 4 
 5 @Id
 6 @GeneratedValue
 7 private Long id;
 8 @Column(name = "stu_name")
 9 private String stuName;
10 
11 ....


注意: get、set方法自行完善

四. 主要总结内容
(1)Repository
(2)CrudRepository
(3)PagingAndSortingRepository
(4)JpaRepository
(5)JpaSpecificationExecutor

1. repository继承图示

 

继承关系是:
JpaRepository 继承PagingAndSortingRepository,PagingAndSortingRepository继承CrudRepository,CrudRepository继承Repository

可以看出:
(1)都是接口
(2)上面的的继承关系中并没有JpaSpecificationExecutor,这个是独立的

2. Repository接口
  先点进去,看看,是一个空接口,也就是一个标记接口

  继承这个接口能干什么?查询
  满足其一定的命名规范去书写方法名,可以不用自己写sql语句,直接执行查询


  示例:

 

  测试:

 

  结果:

 

  解释:我们可以在Repository里自定义方法,但是命名规范是定死的,不是大风刮来的,比如说,方法名的开头一般以 find | get | read 为开头

  看图:

 

  具体的命名规范,建议看官方文档https://docs.spring.io/spring-data/jpa/docs/2.0.7.RELEASE/reference/html/

  总结:
    自定义一个接口,继承Repository接口,满足一定命名规范书写方法名,就可以不用手写sql语句,执行查询操作

3.@Query注解
  上面已经说了,继承Repository接口,即可实现查询,那么增删改查呢中的增删改呢?
  好的,使用@Query注解,可以实现增、删、改。

  准备:

     A. 此时,需要书写JPQL语句,并且需要用到三个注解@Query、@Modifying、@Transactional
     B. 方法分为有参和无参

  (1)以更新操作为例子
     1)这里先以无参方法为例,实现一个修改的操作

 

  一般在service层开启注解

 

  开始测试:

 

  结果:


  2)带参方法,实现一个修改的操作
    传参方式有两种:命名参数、占位符
    先来第一种:
      英文的冒号   ‘ :’ ,后面加上自定义的名字,冒号和名字之间无空格
      这里还漏了一点,使用命名参数传参,需要在参数中使用@Param注解,里面的值要和JPQL里定义参数名的一样

  A. 使用命名参数示例:

 

 

  service层记住开启注解

 

  测试:

 

  结果:

 

  注意:

    其实还有一点,这一点可以和接下来的占位符进行比较,
    当有参方法有两个及以上参数时,比如下面这个,参数的传递顺序随意,因为有@Param限定好了


  B. 使用占位符示例:

 

  英文的  '?' ,后面跟着的1啊、2啊或者3456等等,组合起来就表示第一个占位符,第二个占位符...
  注意:因为使用占位符,参数传递顺序严格按照JPQL语句中的顺序,不能乱,这与使用命名参数传参的不同


  所以,我建议使用命名参数传参,免得错乱!

  (3)如果不熟JPQL语句怎么办?用原生sql语句查询
    将上面那个改造一下

  nativeQuery = true 即为使用原生sql
  注意:因为是原生sql语句,所有记得表名和字段都要和数据库字段属性一一对应起来

  (4)为什么会有JPQL语句?为什么还支持原生sql语句?
    就用官方事先实现好的,以及满足JPA命名规范的自定义方法去查询或者更新不行吗?
    还真不行!
    比如说,我这有个子查询,怎么查?查不了吧。。。
    这里用JPQL或者原生sql就很简单


  (5)like模糊查询
    这里讲讲使用@Query的模糊查询,主要是 '%'的用法,有两种


    1)传递参数时,在参数两边用%

 

    2)直接写在@Query里


    推荐使用第二种,传参就老老实实传参,别瞎折腾

    总结:
      1> 记住  @Query、@Modifying、@Transactional、@Param 这四个注解的用处
      2> 使用JPQL语句可以执行查询、修改、删除的操作,不能进行增加数据的操作
      3> 使用原生sql语句可以实现增的操作,就是nativeQuery = true(上面忘记说了)
      4> 默认情况下,spring Data 的每个方法上都有事务,但都是只读事务(read-only),是无法完成修改数据的操作行为的,所以,若是涉及到对数据进行改动的操作,请开启事务@Transactional
      5> 带参方法传参有两种方式,命名参数、占位符,我个人推荐命名参数
      6> like 模糊查询传参也有两种方式,个人建议直接写在JPQL语句内更好

4. CrudRepository接口
  先点进去,看看,可以看出官方已经定义好了一些常用CRUD的方法

 

  方法都是见名知义啊,就不多做解释了
  举个例子吧:
  之前我们已经写好一个findAll的方法,现在我把他给注释了

 

  然后就报错了

 

  因为我的返回类型和官方的不一样

  

  改改呗:

 

  这种时候,这些简单CRUD方法,就不用自己写了,也就是说,自己既可以不用写sql,也不用写自定义方法,用官方提供的现成的就行

  总结:自定义一个接口,继承CrudRepository接口,直接就可以调用官方提供的一套现成的CRUD方法,美滋滋


5. PagingAndSortingRepository接口
  这个也是见名知义的 --分页、排序用的
  点进去,看看

 

  好的,来实现一个分页排序功能
  在这之前,我先把之前的表删了,重新生成,再造点数据,都是官方提供的deleteAll、save方法


  现在数据库中的数据长这样

 

  (1)分页
  我想把写好的方法给大家看看,之后再解释

 

  然后结果:

 

  每页显示5条记录,第三页,id从16开始,这不扯犊子吗?id不应该从11开始吗?
  这是第一个问题:page的索引是从0开始的,所以,改一下


  结果:

 

  第二个问题:这个id是从11开始了,但是这应该是第三页啊。
  再改

 

 

  (2)分页好了,还有排序

 


 

  总结:PagingAndSortingRepository接口主要就是用来实现分页排序的

6. JpaRepository接口
  老规矩,点进去看看

 

  总结:这个嘛,没什么好说的,看方法名就可以了

7. JpaSpecificationExecutor接口,最后一个

 


  问题:他是用来干嘛的?
  解释:还是用来分页,但是是用他来组合条件分页

  回想一下上面实现的分页功能,除了传进去一个起始页和一个每页显示记录数以及排序条件,还传了什么?
  没了,就这三个。够用吗,不够啊。
  我想带个参数模糊查询不给啊?
  我想带个id比较比较不给啊?

  OK!
  在上面实现分页的基础上,我增加两个条件,一个是模糊查询,一个是id比较
  先看,之后我再解释

 

  结果:

 


  解释一下:
    root: 代表查询的实体类。(这里即为Student)
    criteriaQuery: 可以从中可到Root对象,即告知JPA Criteria查询要查询哪一个实体类, 还可以来添加查询条件,还可以结合EntityManager对象得到最终查询的TypedQuery对象。
    CriteriaBuilder : 用于创建Criteria 相关对象的工厂。当然可以从中获取到Predicate对象
    Predicate 类型,代表一个查询条件

  或者再将上面改改,毕竟参数都是传递过来的,不是大风刮来的


  其实这样还是有问题,思考一下,由于业务的变更,需求变更,即要判断的条件可能更多了
  这种时候,一开始就用一个数组存放条件不够优雅,毕竟数组的大小是写死的
  来来来,换成集合走一波


  总结:当你想用组合条件分页查,继承JpaRepository<T, ID>, JpaSpecificationExecutor<T>呗

  综上,
    日常使用,自定义一个接口,继承JpaRepository接口,
    又想组合条件分页查,继承JpaSpecificationExecutor接口


 

posted @ 2018-05-28 18:34  shadowdoor  阅读(988)  评论(0编辑  收藏  举报