mysql - Hibernate/MySQL 基于唯一键连接表

标签 mysql hibernate hql

我正在使用 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。

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

为什么 hibernate 在不同情况下的工作方式不同?

谢谢!

最佳答案

Q1 Hibernate 的行为完全符合要求。

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

这导致

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

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

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

关于mysql - Hibernate/MySQL 基于唯一键连接表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34923834/

相关文章:

MySQL 插入选择连接

java - 删除语句中的语法错误

java - CrudRepository 中的自定义 SQL 查询

sql-server - 使用 Seam & Hibernate 重试事务的最佳方式

java - 将基于 JOIN 的聚合查询结果映射到 Hibernate 属性

nhibernate - 使用 NHibernate 查询

java - Hibernate HQL join fetch 不递归获取

mysql - 从表mysql中查找最大值字段

php - 如何在mysql中编辑序列化内容

hibernate - 如何在 hibernate 标准投影中进行划分(column1/column2)