Skip to content

Commit bde8b8b

Browse files
committed
连表查询以及自定义sql语句实战
1 parent 8945f82 commit bde8b8b

File tree

6 files changed

+178
-2
lines changed

6 files changed

+178
-2
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
3. **[Spring Boot 异常处理](./docs/advanced/springboot-handle-exception.md)**
3434
4. [使用 spring-boot-devtools 进行热部署](./docs/basis/spring-boot-devtools.md)
3535
5. **[一文搞懂如何在 Spring Boot 中正确使用 JPA](./docs/basis/springboot-jpa.md)**
36-
6. [整合 SpringBoot+Mybatis](./docs/basis/springboot-mybatis.md)[SpirngBoot2.0+ 的 SpringBoot+Mybatis 多数据源配置](./docs/basis/springboot-mybatis-mutipledatasource.md)
36+
6. **[JPA 中非常重要的连表查询就是这么简单]()**
37+
7. [整合 SpringBoot+Mybatis](./docs/basis/springboot-mybatis.md)[SpirngBoot2.0+ 的 SpringBoot+Mybatis 多数据源配置](./docs/basis/springboot-mybatis-mutipledatasource.md)
3738

3839
### 进阶
3940

docs/basis/springboot-jpa-lianbiao.md

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# JPA 连表查询和分页
2+
3+
对于连表查询,在 JPA 中还是非常常见的,由于 JPA 可以在 respository 层自定义 SQL 语句,所以通过自定义 SQL 语句的方式实现连表还是挺简单。这篇文章是在上一篇[入门 JPA](./springboot-jpa)的文章的基础上写的,不了解 JPA 的可以先看上一篇文章。
4+
5+
[上一节](./springboot-jpa)的基础上我们新建了两个实体类,如下:
6+
7+
## 相关实体类创建
8+
9+
`Company.java`
10+
11+
```java
12+
@Entity
13+
@Data
14+
@NoArgsConstructor
15+
public class Company {
16+
@Id
17+
@GeneratedValue(strategy = GenerationType.IDENTITY)
18+
private Long id;
19+
@Column(unique = true)
20+
private String companyName;
21+
private String description;
22+
23+
public Company(String name, String description) {
24+
this.companyName = name;
25+
this.description = description;
26+
}
27+
}
28+
```
29+
30+
`School.java`
31+
32+
```java
33+
@Entity
34+
@Data
35+
@NoArgsConstructor
36+
@AllArgsConstructor
37+
public class School {
38+
@Id
39+
@GeneratedValue(strategy = GenerationType.IDENTITY)
40+
private Long id;
41+
@Column(unique = true)
42+
private String name;
43+
private String description;
44+
}
45+
```
46+
47+
## 自定义 SQL语句实现连表查询
48+
49+
假如我们当前要通过 person 表的 id 来查询 Person 的话,我们知道 Person 的信息一共分布在`Company``School``Person`这三张表中,所以,我们如果要把 Person 的信息都查询出来的话是需要进行连表查询的。
50+
51+
首先我们需要创建一个包含我们需要的 Person 信息的 DTO 对象,我们简单第将其命名为 `UserDTO`,用于保存和传输我们想要的信息。
52+
53+
```java
54+
@Data
55+
@NoArgsConstructor
56+
@Builder(toBuilder = true)
57+
@AllArgsConstructor
58+
public class UserDTO {
59+
private String name;
60+
private int age;
61+
private String companyName;
62+
private String schoolName;
63+
}
64+
```
65+
66+
下面我们就来写一个方法查询出 Person 的基本信息。
67+
68+
```java
69+
/**
70+
* 连表查询
71+
*/
72+
@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +
73+
"from Person p left join Company c on p.companyId=c.id " +
74+
"left join School s on p.schoolId=s.id " +
75+
"where p.id=:personId")
76+
Optional<UserDTO> getUserInformation(@Param("personId") Long personId);
77+
```
78+
79+
可以看出上面的 sql 语句和我们平时写的没啥区别,差别比较大的就是里面有一个 new 对象的操作。
80+
81+
## 自定义 SQL 语句连表查询并实现分页操作
82+
83+
假如我们要查询当前所有的人员信息并实现分页的话,你可以按照下面这种方式来做。可以看到,为了实现分页,我们在`@Query`注解中还添加了 **countQuery** 属性。
84+
85+
```java
86+
@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +
87+
"from Person p left join Company c on p.companyId=c.id " +
88+
"left join School s on p.schoolId=s.id ",
89+
countQuery = "select count(p.id) " +
90+
"from Person p left join Company c on p.companyId=c.id " +
91+
"left join School s on p.schoolId=s.id ")
92+
Page<UserDTO> getUserInformationList(Pageable pageable);
93+
```
94+
95+
实际使用:
96+
97+
```java
98+
//分页选项
99+
PageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.DESC, "age");
100+
Page<UserDTO> userInformationList = personRepository.getUserInformationList(pageRequest);
101+
//查询结果总数
102+
System.out.println(userInformationList.getTotalElements());// 6
103+
//按照当前分页大小,总页数
104+
System.out.println(userInformationList.getTotalPages());// 2
105+
System.out.println(userInformationList.getContent());
106+
```
107+
108+
## 加餐:自定以SQL语句的其他用法
109+
110+
### IN 查询
111+
112+
在 sql 语句中加入我们需要筛选出符合几个条件中的一个的情况下,可以使用 IN 查询,对应到 JPA 中也非常简单。比如下面的方法就实现了,根据名字过滤需要的人员信息。
113+
114+
```java
115+
@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +
116+
"from Person p left join Company c on p.companyId=c.id " +
117+
"left join School s on p.schoolId=s.id " +
118+
"where p.name IN :peopleList")
119+
List<UserDTO> filterUserInfo(List peopleList);
120+
```
121+
122+
实际使用:
123+
124+
```java
125+
List<String> personList=new ArrayList<>(Arrays.asList("person1","person2"));
126+
List<UserDTO> userDTOS = personRepository.filterUserInfo(personList);
127+
```
128+
129+
### BETWEEN 查询
130+
131+
查询满足某个范围的值。比如下面的方法就实现查询满足某个年龄范围的人员的信息。
132+
133+
```java
134+
@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +
135+
"from Person p left join Company c on p.companyId=c.id " +
136+
"left join School s on p.schoolId=s.id " +
137+
"where p.age between :small and :big")
138+
List<UserDTO> filterUserInfoByAge(int small,int big);
139+
```
140+
141+
实际使用:
142+
143+
```java
144+
List<UserDTO> userDTOS = personRepository.filterUserInfoByAge(19,20);
145+
```
146+

docs/basis/springboot-jpa.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# 一文搞懂如何在 Spring Boot 中正确使用 JPA
2+
13
JPA 这部分内容上手很容易,但是涉及到的东西还是挺多的,网上大部分关于 JPA 的资料都不是特别齐全,大部分用的版本也是比较落后的。另外,我下面讲到了的内容也不可能涵盖所有 JPA 相关内容,我只是把自己觉得比较重要的知识点总结在了下面。我自己也是参考着官方文档写的,[官方文档](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference)非常详细了,非常推荐阅读一下。这篇文章可以帮助对 JPA 不了解或者不太熟悉的人来在实际项目中正确使用 JPA。
24

35
项目代码基于 Spring Boot 最新的 2.1.9.RELEASE 版本构建(截止到这篇文章写完),另外,新建项目就不多说了,前面的文章已经很详细介绍过。

source-code/basis/jpa-demo/src/main/java/github/snailclimb/jpademo/model/po/School.java

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33

44
import lombok.AllArgsConstructor;
5-
import lombok.Builder;
65
import lombok.Data;
76
import lombok.NoArgsConstructor;
87

source-code/basis/jpa-demo/src/main/java/github/snailclimb/jpademo/repository/PersonRepository.java

+11
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,15 @@ public interface PersonRepository extends JpaRepository<Person, Long> {
5252
"left join School s on p.schoolId=s.id ")
5353
Page<UserDTO> getUserInformationList(Pageable pageable);
5454

55+
@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +
56+
"from Person p left join Company c on p.companyId=c.id " +
57+
"left join School s on p.schoolId=s.id " +
58+
"where p.name IN :peopleList")
59+
List<UserDTO> filterUserInfo(List peopleList);
60+
61+
@Query(value = "select new github.snailclimb.jpademo.model.dto.UserDTO(p.name,p.age,c.companyName,s.name) " +
62+
"from Person p left join Company c on p.companyId=c.id " +
63+
"left join School s on p.schoolId=s.id " +
64+
"where p.age between :small and :big")
65+
List<UserDTO> filterUserInfoByAge(int small,int big);
5566
}

source-code/basis/jpa-demo/src/test/java/github/snailclimb/jpademo/repository/PersonRepositoryTest2.java

+17
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.springframework.test.context.jdbc.Sql;
1414
import org.springframework.test.context.junit4.SpringRunner;
1515

16+
import java.util.ArrayList;
17+
import java.util.Arrays;
1618
import java.util.List;
1719
import java.util.Optional;
1820

@@ -49,4 +51,19 @@ public void should_get_user_info_list() {
4951
System.out.println(userInformationList.getTotalPages());// 2
5052
System.out.println(userInformationList.getContent());
5153
}
54+
55+
@Sql(scripts = {"classpath:/init.sql"})
56+
@Test
57+
public void should_filter_user_info() {
58+
List<String> personList=new ArrayList<>(Arrays.asList("person1","person2"));
59+
List<UserDTO> userDTOS = personRepository.filterUserInfo(personList);
60+
System.out.println(userDTOS);
61+
}
62+
63+
@Sql(scripts = {"classpath:/init.sql"})
64+
@Test
65+
public void should_filter_user_info_by_age() {
66+
List<UserDTO> userDTOS = personRepository.filterUserInfoByAge(19,20);
67+
System.out.println(userDTOS);
68+
}
5269
}

0 commit comments

Comments
 (0)