java - 为什么 Hibernate @OneToOne 执行多个选择查询而不是一个?
问题描述
这是我的实体:
@Entity
public class ProductStateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@OneToOne
@JoinColumn(name = "product_id", nullable = false)
private ProductEntity product;
// other fields
}
@Entity
public class ProductEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
// other fields
}
如果我这样提出请求:
session.get(ProductStateEntity.class, 10);
SQL 是这样形成的:
SELECT product_states.id, product_states.product_id, products.id, -- other columns
FROM product_states
INNER JOIN products ON product_states.product_id=products.id
WHERE product_states.id=10
到目前为止,一切都很好,使用INNER JOIN
.
如果您以这种方式提出请求:
session.createQuery("from ProductStateEntity where id = :id")
.setParameter("id", 10)
.list()
SQL 是这样形成的:
SELECT product_states.id, product_states.product_id, -- other columns
FROM product_states
WHERE product_states.id=10;
SELECT products.id, -- other columns
FROM products
WHERE products.id=10
在这种情况下,发出了 2 个请求。首先在 product_states 中进行查询,然后在 products 中进行查询。
这还不是全部,现在我们将发出这样一个请求,它一次接收 4 条 4 id 的记录:
session.createQuery("from ProductStateEntity where id in :ids")
.setParameter("ids", Arrays.asList(10, 11, 12, 13))
.list();
SQL 是这样形成的:
SELECT product_states.id, product_states.product_id, -- other columns
FROM product_states
WHERE product_states.id IN (10, 11, 12, 13);
SELECT products.id, -- other columns
FROM products
WHERE products.id=10;
SELECT products.id, -- other columns
FROM products
WHERE products.id=11;
SELECT products.id, -- other columns
FROM products
WHERE products.id=12;
SELECT products.id, -- other columns
FROM products
WHERE products.id=13;
在这种情况下,发出 5 个请求。首先,在product_states 中发出请求,获得所有产品的id,然后在1 个请求上完成,接收4 个产品中的每一个。
添加join fetch
到上一个查询:
session.createQuery("from ProductStateEntity p join fetch p.product where p.id in :ids")
.setParameter("ids", Arrays.asList(10, 11, 12, 13))
.list();
SQL 是这样形成的:
SELECT product_states.id, products.id, product_states.product_id, -- other columns
FROM product_states
INNER JOIN products ON product_states.product_id=products.id
WHERE product_states.id IN (10, 11, 12, 13)
因此,仅使用 1 个请求INNER JOIN
,这是我想要实现的。
所以问题是:
- 为什么需要
join fetch
明确指定 increateQuery
?可以做出这种默认行为吗?毕竟,使用连接的单个查询总比很多好。 - 为什么在不指定的情况下
join fetch
,其他选择查询不会与 合并为一个id in (...)
?相反,Hibernate 一次选择一个。这个可以定制吗?
解决方案
n+1
获取策略是 Hibernate 的默认策略 - 只是因为,如文档中所述
这些默认值对大多数应用程序中的大多数关联都有意义
要全局更改此行为,您可以设置hibernate.default_batch_fetch_size
,并且您会在互联网上找到一些关于如何设置正确值以及为什么设置的主题
还有一件事——普遍认为fetch join
是解决每个问题的方法,但事实并非如此。我们必须记住笛卡尔积问题。
获取策略取决于我们的应用程序是如何工作的、环境设置是什么(例如数据库连接中的延迟)、我们使用什么数据模型以及许多其他事情。没有一个适合每个人的好的解决方案,这就是为什么我们在 Hibernate 中有很多获取策略的原因
推荐阅读
- javascript - 仅当 Chrome DevTools 打开时才会弹出警报
- python - 如何为 Python Swigged C++ 对象创建和分配回调函数
- python - Django DRF - 通过权限限制对列表视图的访问
- redux - 如何为 reduxForm() 设置全局默认值
- node.js - 在 node/express.js 子应用之间共享视图和静态文件
- sql - 将 SQL Developer 连接到 Redshift
- java - JSF f:convertNumber 在面板中有效,但在对话框中无效
- sass - 如何通过 SASS 更改 Bootstrap 4 的边框底部宽度?
- javascript - 在 React Native 项目中,为什么在导入中将顶级目录称为“app”?
- git - 为什么詹金斯从下载的 git repo 中删除空目录?