我正在使用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使用&#34; CROSS JOIN&#34; ,为HQL2使用&#34; INNER JOIN&#34; 。
我不明白为什么它在HQL1上使用交叉连接。
问题3:
如果使用主键进行连接,则一切正常:hibernate遵循LAZY关联e没有CROSS JOIN用于隐式连接。
那么,我应该避免使用唯一键作为外键吗?
为什么hibernate对每种情况的工作方式都不同?
谢谢!
答案 0 :(得分:0)
Q1 Hibernate的行为与请求完全相同。
您正在获取给定父级(表A)的所有子级(表A),这些子级由您要求获取父级 lazy 的parant键和标识。
这导致
1)将子节点连接到父节点(您需要连接才能按键识别父节点),但由于 lazy 策略,您将忽略父节点数据。
2)在下一步中,您可以通过键获取父数据(只有一个选择,因为关系是多对一)。
我的意见,在这种情况下 - 懒惰的一个识别实体 - 是反作用的。