为什么 Hibernate @OneToOne 执行多个选择查询而不是一个?

gom*_*n1d 5 java orm hibernate hql

这是我的实体:

@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
}
Run Code Online (Sandbox Code Playgroud)

如果我这样提出请求:

session.get(ProductStateEntity.class, 10);
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切顺利,使用INNER JOIN.


如果您以这种方式提出请求:

session.createQuery("from ProductStateEntity where id = :id")
            .setParameter("id", 10)
            .list()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

在本例中,提出了 2 个请求。首先在product_states 中进行查询,然后在products 中进行查询。


这还不是全部,现在我们将发出这样一个请求,它一次接收 4 个 id 的 4 条记录:

session.createQuery("from ProductStateEntity where id in :ids")
            .setParameter("ids", Arrays.asList(10, 11, 12, 13))
            .list();
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

在本例中,提出了 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();
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

因此,只发出 1 个请求INNER JOIN,这就是我想要实现的目标。


所以问题是:

  1. 为什么需要join fetch在 中明确指定createQuery?可以做出这种默认行为吗?毕竟,带有连接的单个查询比大量查询要好。
  2. 为什么在不指定 的情况下join fetch,附加的选择查询不会与 组合成一个id in (...)?相反,Hibernate 一次选择一个。这个可以定制吗?

m.a*_*icz 0

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

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

要在全局范围内更改此行为,您可以进行设置hibernate.default_batch_fetch_size,并且您会在互联网上找到一些有关如何设置正确值以及原因的主题

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

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