Hibernate总是运行冗余查询

时间:2017-09-26 02:47:01

标签: java mysql hibernate one-to-one

我的数据模型中存在OneToOne关系,而hibernate总是查询这两个实体以生成结果集。

这是数据模型

@Entity
public class C1 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, targetEntity = C2.class)
    private C2 c2;

    //... other stuff
}


@Entity
public class C2 extends OtherClassOutOfDomain {

   @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "c2")
    private C1 c1;

    //... other stuff
}

Hibernate生成我的模式作为两个表,C1表有一个C2的外键,这对我来说是完美的,因为我会更经常使用C1。

BUT

每次我查询C1时,hibernate生成1个查询,每行连接两个实体数据,并为第一个结果中的每一行生成N个查询(即使我进入结果集)

例如

Hibernate (just one): 
    select
        this_.id as id1_2_1_,
        this_.c2_id as authDat22_2_1_,
        this_.bio as bio2_2_1_,
        this_.blocked as blocked3_2_1_,
        this_.commentsAmount as comments4_2_1_,
        this_.confirmed as confirme5_2_1_,
        this_.deleted as deleted6_2_1_,
        c22_.id as id1_0_0_,
        c22_.adid as adid2_0_0_,
    from
        c1 this_ 
    inner join
        c2 c22_
            on this_.authData_id=c22_.id

Hibernate (N times as the size of previous query): 
    select
        this_.id as id1_2_1_,
        this_.c2_id as authDat22_2_1_,
        this_.bio as bio2_2_1_,
        this_.blocked as blocked3_2_1_,
        this_.commentsAmount as comments4_2_1_,
        this_.confirmed as confirme5_2_1_,
        this_.deleted as deleted6_2_1_,
        c22_.id as id1_0_0_,
        c22_.adid as adid2_0_0_,
    from
        c1 this_ 
    inner join
        c2 c22_
            on this_.authData_id=c22_.id
    where
            this_.authData_id=?
.....repeat
.....repeat
.....repeat

重复查询的结果被放在第一个大查询的行中...是否有办法避免这些不必要的请求?我试着设置为懒惰,但它不起作用

我正在运行以获得此行为的代码很简单

HibernateUtils.createNewSession().createCriteria(C1.class).list();

我甚至没有在触发嵌套查询之前访问结果

我正在使用hibernate 5.10和mysql 5.7.17

2 个答案:

答案 0 :(得分:0)

我得到了一个解决方案,但我还没有完全明白为什么。

由于映射OneToOne与JPA hibernate的关系会将外键放在具有" targetEntity"的实体上。属性(具有属性的实体,没有设置为属性值的实体)

当一个在其结构中有外键的实体查询时,hibernate将自动查询嵌套实体(我不知道原因)

要解决我以前的相关问题,我只需要将注释更改为

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, mappedBy= "c1")
private C2 c2; 

@OneToOne(fetch = FetchType.LAZY, targetEntity = C1.class) 
private C1 c1;

答案 1 :(得分:0)

记住这两件事。

OneToOne的默认提取策略是EAGER。

如果关联不可为空,则LAZY只能在OneToOne关联上工作。

您的问题类似于N + 1选择问题

解决N + 1 SELECTs问题:

HQL抓取加入

无论

这    C1 c1  左连接获取     c1.c2

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, mappedBy= "c1")
@Fetch(FetchMode.JOIN) 
private C2 c2;

和第二课

@OneToOne(fetch = FetchType.LAZY, mappedBy = "c2")
@Fetch(FetchMode.JOIN) 
private C1 c1;