【问题标题】:Hibernate/MySQL join tables based on unique key基于唯一键的 Hibernate/MySQL 连接表
【发布时间】:2016-04-27 16:52:41
【问题描述】:

我正在使用 hibernate 4.3.11.Final 和 MySql 5.6。

我正在尝试理解以下行为:

表格:

create table table_a (
    id integer not null auto_increment,
    code_table_a varchar(12) not null,
    desc_table_a varchar(50) not null,
    primary key (id),
    constraint ux_code_table_a unique (code_table_a)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

create table table_b (
    id integer not null auto_increment,
    code_table_b varchar(12) not null,
    desc_table_b varchar(50) not null,
    code_table_a varchar(12) not null,
    primary key (id),
    constraint ux_code_table_b unique (code_table_b),
    constraint ix_table_b_code_table_a_fk foreign key (code_table_a) references table_a (code_table_a)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

请注意,table_b 上的外键引用了 table_a 中的唯一键(不是主键)。

映射:

@Entity
@Table(name = "table_a")
public class TableA implements Serializable {

    private static final long serialVersionUID = 8419151902341044850L;

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

    @Column(name = "code_table_a")
    private String code;

    @Column(name = "desc_table_a")
    private String description;

    // hashCode and equals are based on the "code" property only

    // getters / setters
}

@Entity
@Table(name = "table_b")
public class TableB implements Serializable {

    private static final long serialVersionUID = 943565980437511902L;

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

    @Column(name = "code_table_b")
    private String code;

    @Column(name = "desc_table_b")
    private String description;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "code_table_a", referencedColumnName = "code_table_a", unique = true)
    private TableA tableA;

    // hashCode and equals are based on the "code" property only

    // getters / setters
}

HQL 1:

public List<TableB> findByCodeTableA(String codeTableA) {
    StringBuilder select = new StringBuilder("select tableB from TableB tableB ");
    select.append("where tableB.tableA.code = :codeTableA ");
    // select.append("inner join tableB.tableA tableA ");
    // select.append("where tableA.code = :codeTableA ");

    Session session = sessionFactory.getCurrentSession();

    Query query = session.createQuery(select.toString());
    query.setParameter("codeTableA", codeTableA);

    List<TableB> lista = new ArrayList<>();
    lista.addAll(query.list());

    return lista;
}

HQL 1 的日志:

21 Jan 2016 09:33:17,505 DEBUG SQL - 
    /* select
        tableB 
    from
        TableB tableB 
    where
        tableB.tableA.code = :codeTableA  */ select
            tableb0_.id as id1_1_,
            tableb0_.code_table_b as code_tab2_1_,
            tableb0_.desc_table_b as desc_tab3_1_,
            tableb0_.code_table_a as code_tab4_1_ 
        from
            table_b tableb0_ cross 
        join
            table_a tablea1_ 
        where
            tableb0_.code_table_a=tablea1_.code_table_a 
            and tablea1_.code_table_a=?
21 Jan 2016 09:33:17,560 DEBUG SQL - 
    /* load com.baldotech.hibernatepg.model.TableA */ select
        tablea0_.id as id1_0_0_,
        tablea0_.code_table_a as code_tab2_0_0_,
        tablea0_.desc_table_a as desc_tab3_0_0_ 
    from
        table_a tablea0_ 
    where
        tablea0_.code_table_a=?
21 Jan 2016 09:33:17,577 DEBUG SQL - 
    /* load com.baldotech.hibernatepg.model.TableA */ select
        tablea0_.id as id1_0_0_,
        tablea0_.code_table_a as code_tab2_0_0_,
        tablea0_.desc_table_a as desc_tab3_0_0_ 
    from
        table_a tablea0_ 
    where
        tablea0_.code_table_a=?

HQL 2:

public List<TableB> findByCodeTableA(String codeTableA) {
    StringBuilder select = new StringBuilder("select tableB from TableB tableB ");
    // select.append("where tableB.tableA.code = :codeTableA ");
    select.append("inner join tableB.tableA tableA ");
    select.append("where tableA.code = :codeTableA ");

    Session session = sessionFactory.getCurrentSession();

    Query query = session.createQuery(select.toString());
    query.setParameter("codeTableA", codeTableA);

    List<TableB> lista = new ArrayList<>();
    lista.addAll(query.list());

    return lista;
}

HQL 2 的日志输出:

21 Jan 2016 09:32:17,733 DEBUG SQL - 
    /* select
        tableB 
    from
        TableB tableB 
    inner join
        tableB.tableA tableA 
    where
        tableA.code = :codeTableA  */ select
            tableb0_.id as id1_1_,
            tableb0_.code_table_b as code_tab2_1_,
            tableb0_.desc_table_b as desc_tab3_1_,
            tableb0_.code_table_a as code_tab4_1_ 
        from
            table_b tableb0_ 
        inner join
            table_a tablea1_ 
                on tableb0_.code_table_a=tablea1_.code_table_a 
        where
            tablea1_.code_table_a=?
21 Jan 2016 09:32:17,777 DEBUG SQL - 
    /* load com.baldotech.hibernatepg.model.TableA */ select
        tablea0_.id as id1_0_0_,
        tablea0_.code_table_a as code_tab2_0_0_,
        tablea0_.desc_table_a as desc_tab3_0_0_ 
    from
        table_a tablea0_ 
    where
        tablea0_.code_table_a=?
21 Jan 2016 09:32:17,797 DEBUG SQL - 
    /* load com.baldotech.hibernatepg.model.TableA */ select
        tablea0_.id as id1_0_0_,
        tablea0_.code_table_a as code_tab2_0_0_,
        tablea0_.desc_table_a as desc_tab3_0_0_ 
    from
        table_a tablea0_ 
    where
        tablea0_.code_table_a=?

问题 1:

如您所见,@ManyToOne 关联被标记为 LAZY:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "code_table_a", referencedColumnName = "code_table_a", unique = true)
private TableA tableA;

但是日志显示 Hibernate 正在为每个实体 TableB 加载实体 TableA。这是为什么呢?

问题 2:

HQL1 使用隐式连接:

"where tableB.tableA.code = :codeTableA "

HQL2 使用显式连接:

"inner join tableB.tableA tableA where tableA.code = :codeTableA "

日志显示 hibernate 对 HQL1 使用 "CROSS JOIN",对 HQL2 使用 "INNER JOIN"。

我不明白为什么它在 HQL1 上使用交叉联接。

问题 3:

如果使用主键进行连接,一切正常:hibernate 尊重 LAZY 关联 e 没有 CROSS JOIN 用于隐式连接。

那么,我应该避免使用唯一键作为外键吗?

为什么休眠对每种情况的工作方式不同?

谢谢!

【问题讨论】:

    标签: mysql hibernate hql


    【解决方案1】:

    Q1Hibernate 的行为完全符合要求。

    您正在获取由父键标识的给定父级(表 A)的所有子级(表 B)并且您请求获取父级惰性。 p>

    这导致

    1) 子节点与父节点的连接(您需要连接才能通过键识别父节点),但由于 lazy 策略,您忽略了父数据。

    2) 在下一步中,您通过键获取父数据(只有一个选择,因为关系是多对一的)。

    我的意见,在这种情况下 - 懒惰地识别实体 - 是适得其反的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-28
      • 1970-01-01
      • 2016-06-07
      • 1970-01-01
      • 2019-01-21
      • 2021-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多