Spring JPA Ⅹ 联表查询 之 ManyToMany
前言
源码
@ManyToMany 注解实现多对多关系映射。我们还是以上面用户和房子为例(博主是多想要一套房子啊),毕竟一个用户可以拥有多套房子,而一套房子也可以写多个人的名字。 老规矩,实例之前先看看源码:
public @interface ManyToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default LAZY;
String mappedBy() default "";
}
注解详情请见 注解属性详解 。其中需要注意的是 @ManyToMany 没有 orphanRemoval 的属性。多对多的情况下不能级联删除也能理解,毕竟不是一个人能说了算的。
单向联表
实例
user 实体
@Entity
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
@ManyToMany
private List<House> house;
}
house 实体
@Entity
@Data
public class House {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String addr;
}
小贴士
实例运行之后,会在数据库中生成一个中间表(user_house),这个表就是用来维护用户和房子映射关系的。
执行请求/user/findById?id=1
,控制台打印如下:
Hibernate:
select
house0_.user_id as user_id1_3_0_,
house0_.house_id as house_id2_3_0_,
house1_.id as id1_1_1_,
house1_.addr as addr2_1_1_
from
user_house house0_
inner join
house house1_
on house0_.house_id=house1_.id
where
house0_.user_id=?
查询结果
Optional[User(id=1, name=lili, age=11, house=[House(id=1, addr=江苏南京), House(id=2, addr=江苏无锡), House(id=3, addr=江苏苏州)])]
双向联表
实例
user 实体
@Entity
@Data
@JsonIgnoreProperties(value = {"hibernateLazyInitializer"})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
@ManyToMany
@JsonIgnore
public List<House> house;
}
house 实体
@Entity
@Data
public class House {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String addr;
@ManyToMany(mappedBy = "house")
@JsonIgnore
private List<User> user;
}
小贴士
这里的 @JsonIgone 的注解就是为了解决堆栈溢出的问题。详情请见 Spring JPA 错题集。
house
类中的user
需要添加mappedBy = "house"
,表示house
是被动管理。如果不添加的话,系统会再生成一个中间表(house_user),这样一来,house
需要自己管理。在使用house
获取user
信息的时候会依赖中间表(house_user),导致user
信息获取失败。
userControl 类
@GetMapping("findById")
public Optional<User> findById(int id){
Optional<User> users = userService.findById(id);
users.get().getHouse().forEach(v->{
System.out.println(v.getId() + "-"+ v.getAddr());
});
return userService.findById(id);
}
执行请求 /user/findById?id=33
,控制台打印如下:
Hibernate:
select
user0_.id as id1_2_0_,
user0_.age as age2_2_0_,
user0_.name as name3_2_0_
from
user user0_
where
user0_.id=?
[nio-7777-exec-7] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [33]
Hibernate:
select
house0_.user_id as user_id1_3_0_,
house0_.house_id as house_id2_3_0_,
house1_.id as id1_1_1_,
house1_.addr as addr2_1_1_
from
user_house house0_
inner join
house house1_
on house0_.house_id=house1_.id
where
house0_.user_id=?
[nio-7777-exec-7] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [33]
1-南京
2-苏州
3-无锡
houseControl 类
@RequestMapping("findById")
public Optional<House> findById(int id){
Optional<House> houses = houseService.findById(id);
houses.get().getUser().forEach(v->{
System.out.println(v.getName() + "-"+ v.getAge());
});
return houseService.findById(id);
}
执行请求 /house/findById?id=1
,控制台打印如下:
Hibernate:
select
house0_.id as id1_1_0_,
house0_.addr as addr2_1_0_
from
house house0_
where
house0_.id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
Hibernate:
select
user0_.house_id as house_id2_3_0_,
user0_.user_id as user_id1_3_0_,
user1_.id as id1_2_1_,
user1_.age as age2_2_1_,
user1_.name as name3_2_1_
from
user_house user0_
inner join
user user1_
on user0_.user_id=user1_.id
where
user0_.house_id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
dada-22
tt-22
iii-221
转载自:https://juejin.cn/post/7229220276847149114