首页 > 解决方案 > 为什么 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,这是我想要实现的。


所以问题是:

  1. 为什么需要join fetch明确指定 in createQuery?可以做出这种默认行为吗?毕竟,使用连接的单个查询总比很多好。
  2. 为什么在不指定的情况下join fetch,其他选择查询不会与 合并为一个id in (...)?相反,Hibernate 一次选择一个。这个可以定制吗?

标签: javahibernateormhql

解决方案


n+1获取策略是 Hibernate 的默认策略 - 只是因为,如文档中所述

这些默认值对大多数应用程序中的大多数关联都有意义

要全局更改此行为,您可以设置hibernate.default_batch_fetch_size,并且您会在互联网上找到一些关于如何设置正确值以及为什么设置的主题

还有一件事——普遍认为fetch join是解决每个问题的方法,但事实并非如此。我们必须记住笛卡尔积问题

获取策略取决于我们的应用程序是如何工作的、环境设置是什么(例如数据库连接中的延迟)、我们使用什么数据模型以及许多其他事情。没有一个适合每个人的好的解决方案,这就是为什么我们在 Hibernate 中有很多获取策略的原因


推荐阅读