java - 如何防止在春季执行第二次查询?
问题描述
从数据库中获取某些实体时,我遇到了 JPA/Hibernate 问题。问题是它执行两个查询,即使你第一个查询也足以收集或我需要实体的数据。
我所描述的实体类型具有自我参考。这里是:
@Data
@Entity
@Table(name = "franchises")
@EntityListeners(AuditingEntityListener.class)
@NamedEntityGraphs({
@NamedEntityGraph(
name = "Franchise.Parent.Country",
attributeNodes = {
@NamedAttributeNode("parent"),
@NamedAttributeNode("country"),
}
),
})
public class Franchise {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "name")
private String name;
@Enumerated(EnumType.STRING)
@Column(name = "type")
private FranchiseType type;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Franchise parent;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "country_id")
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Country country;
}
这是存储库:
@Repository
public interface IFranchiseRepository extends JpaRepository<Franchise, Long>,
JpaSpecificationExecutor<Franchise>,
QuerydslPredicateExecutor<Franchise>,
FranchiseRepositoryCustom
{
@EntityGraph("Franchise.Parent.Country")
Optional<Franchise> findWithParentAndCountryById(long id);
}
现在在控制器中我有这个代码:
@GetMapping("/api/franchises/{franchise}")
public FranchiseDTO getFranchise(@PathVariable("franchise") long franchiseId) {
var f = franchiseRepository.findWithParentAndCountryById(franchiseId).get();
return null; // Do not worry about this statement, I am yet to map ti to DTO
}
当我调用这个 api 端点时,我可以在控制台日志中看到它正在执行两个查询:
SELECT
franchise0_.id AS id1_6_0_,
franchise1_.id AS id1_6_1_,
country2_.id AS id1_3_2_,
franchise0_.country_id AS country_6_6_0_,
franchise0_.created_at AS created_2_6_0_,
franchise0_.name AS name3_6_0_,
franchise0_.parent_id AS parent_i7_6_0_,
franchise0_.type AS type4_6_0_,
franchise0_.updated_at AS updated_5_6_0_,
franchise1_.country_id AS country_6_6_1_,
franchise1_.created_at AS created_2_6_1_,
franchise1_.name AS name3_6_1_,
franchise1_.parent_id AS parent_i7_6_1_,
franchise1_.type AS type4_6_1_,
franchise1_.updated_at AS updated_5_6_1_,
country2_.alpha2_code AS alpha2_3_2_,
country2_.alpha3_code AS alpha3_3_2_,
country2_.created_at AS created_4_3_2_,
country2_.name AS name5_3_2_,
country2_.updated_at AS updated_6_3_2_
FROM
franchises franchise0_
LEFT OUTER JOIN franchises franchise1_ ON
franchise0_.parent_id = franchise1_.id
LEFT OUTER JOIN countries country2_ ON
franchise0_.country_id = country2_.id
WHERE
franchise0_.id = 3;
SELECT
franchise0_.id AS id1_6_0_,
franchise0_.country_id AS country_6_6_0_,
franchise0_.created_at AS created_2_6_0_,
franchise0_.name AS name3_6_0_,
franchise0_.parent_id AS parent_i7_6_0_,
franchise0_.type AS type4_6_0_,
franchise0_.updated_at AS updated_5_6_0_
FROM
franchises franchise0_
WHERE
franchise0_.id = 135
这是我在数据库中的数据:
|-----|-------------|---------------|-----------|------------|
| id | name | type | parent_id | country_id |
|-----|-------------|---------------|-----------|------------|
| 135 | Franchise A | INTERNATIONAL | NULL | NULL |
| 2 | Franchise B | MASTER | 135 | 1 |
| 3 | Franchise C | REGIONAL | 2 | 1 |
| 4 | Franchise D | REGIONAL | 2 | 1 |
|-----|-------------|---------------|-----------|------------|
因此,通过查看执行的查询,我可以看到(并测试)我需要的所有数据都是使用第一个查询 Franchise+Parent+Country 获取的。但是,随后执行第二个查询以加载我不需要的父级的父级...
有人能告诉我我在做什么错吗?为什么要执行两个查询而不是只执行一个?
解决方案
改变这个:
@ManyToOne(fetch = FetchType.LAZY)
private Franchise parent;
至
@ManyToOne(fetch = FetchType.EAGER)
private Franchise parent;
并尝试。
推荐阅读
- android - 在以编程方式安装 apk 之前出现错误 Android 8.1
- c++ - 指针在 C++ 中为不同的变量存储相同的地址
- android - 如何在服务停止时更新通知 - Android
- git - 不要推送文件中的更改
- python - 构造模型的新实例时,如何强制 SQLAlchemy 转换属性值?
- jquery - 模态加载后如何执行函数?
- postgresql - 使用 PostgreSQL 全文搜索搜索名为“Don”的用户
- sql - 数据库规范化问题的最佳实践
- vb.net - 请帮助 Veracode 发布 CWE 15 External Control of System or Configuration Setting n 文件名
- python-3.7 - 有没有将空格分隔文件更改为逗号分隔文件的好方法?