Sot*_*lis 14 java hibernate jpa hql
我有以下查询和方法
private static final String FIND = "SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";
@Override
public Domain find(Long domainId) {
Query query = getCurrentSession().createQuery(FIND);
query.setLong("domainId", domainId);
return (Domain) query.uniqueResult();
}
Run Code Online (Sandbox Code Playgroud)
与Domain作为
@Entity
@Table
public class Domain {
@Id
@GenericGenerator(name = "generator", strategy = "increment")
@GeneratedValue(generator = "generator")
@Column(name = "domain_id")
private Long domainId;
@Column(nullable = false, unique = true)
@NotNull
private String name;
@Column(nullable = false)
@NotNull
@Enumerated(EnumType.STRING)
private DomainType type;
@OneToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.EAGER)
@JoinTable(joinColumns = {
@JoinColumn(name = "domain_id")
}, inverseJoinColumns = {
@JoinColumn(name = "code")
})
@NotEmpty
@Valid // needed to recur because we specify network codes when creating the domain
private Set<NetworkCode> networkCodes = new HashSet<>();
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(joinColumns = {
@JoinColumn(name = "parent", referencedColumnName = "domain_id")
}, inverseJoinColumns = {
@JoinColumn(name = "child", referencedColumnName = "domain_id")
})
private Set<Domain> operators = new HashSet<>();
// more
}
Run Code Online (Sandbox Code Playgroud)
我希望这个单一的查询可以获取Set<NetworkCode>和Set<Domain>关系,但事实并非如此.假设DomainI查询有两个运算符,Hibernate将执行1 + 2*2 = 5个查询
Hibernate: select distinct domain0_.domain_id as domain1_1_0_, domain2_.domain_id as domain1_1_1_, networkcod4_.code as code2_2_, domain0_.name as name1_0_, domain0_.type as type1_0_, domain2_.name as name1_1_, domain2_.type as type1_1_, operators1_.parent as parent1_0__, operators1_.child as child4_0__, networkcod3_.domain_id as domain1_1_1__, networkcod3_.code as code5_1__ from domain domain0_ left outer join domain_operators operators1_ on domain0_.domain_id=operators1_.parent left outer join domain domain2_ on operators1_.child=domain2_.domain_id inner join domain_network_codes networkcod3_ on domain0_.domain_id=networkcod3_.domain_id inner join network_code networkcod4_ on networkcod3_.code=networkcod4_.code where domain0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?
Run Code Online (Sandbox Code Playgroud)
我猜这是因为我加入了运营商Domain元素,但他们必须自己加入.
是否有可以执行的HQL查询?
Dil*_*eep 13
Hibernate关系适用于不同的获取策略.. !!
Hibernate提供了4种检索数据的策略:
选择
@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id")
@Fetch(FetchMode.SELECT)
Run Code Online (Sandbox Code Playgroud)
在此方法中,有多个SQL被触发.触发第一个用于检索Parent表中的所有记录.其余的被触发以检索每个父记录的记录.这基本上是N + 1问题.第一个查询从数据库中检索N个记录,在本例中为N个父记录.对于每个Parent,新查询将检索Child.因此,对于N Parent,N查询从Child表中检索信息.
加入
@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id")
@Fetch(FetchMode.JOIN)
Run Code Online (Sandbox Code Playgroud)
这与SELECT获取策略类似,不同之处在于所有数据库检索都在JOIN提取中预先进行,而不像SELECT那样需要它.这可以成为重要的性能考虑因素.
子查询
@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id")
@Fetch(FetchMode.SUBSELECT)
Run Code Online (Sandbox Code Playgroud)
触发了两个SQL.一个用于检索所有Parent,另一个在WHERE子句中使用SUBSELECT查询来检索具有匹配父ID的所有子项.
批量
@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id")
@@BatchSize(size=2)
Run Code Online (Sandbox Code Playgroud)
批量大小映射到其子项被检索的父级数.所以我们可以指定一次获取的记录数.但是将执行多个查询.!!
一对多和多对多允许 - 加入,选择和子选择
多对一和一对一允许 - 加入和选择
Hibernate也区分(何时获取关联)
1. 立即取货 -
加载Parent时立即获取关联,集合或属性.(懒惰="假")
2. 懒人收集 -
当应用程序调用该集合上的操作时,将获取集合.(这是集合的默认值.(lazy ="true")
3." 非常懒 "的集合取物 -
根据需要从数据库访问集合的各个元素.除非绝对需要(适用于非常大的集合),否则Hibernate会尝试不将整个集合提取到内存中(lazy ="extra")
4. 代理提取 -
当在关联对象上调用除标识符getter之外的方法时,将获取单值关联.(懒惰="代理")
5." 无代理 "获取 -
访问实例变量时获取单值关联.与代理提取相比,这种方法不那么懒惰.(lazy ="no-proxy")
6. 懒惰属性获取 -
访问实例变量时,将获取属性或单值关联.(懒惰="真")
一对多和多对多允许立即,懒惰,超级懒惰
多对一和一对一允许立即代理,无代理
And*_*i I 12
如果您知道树中只有两个级别,那么您是否考虑过加入更深层次的级别.像下面的东西?
SELECT DISTINCT domain FROM Domain domain
LEFT OUTER JOIN FETCH domain.operators operators1
LEFT OUTER JOIN FETCH domain.networkCodes
LEFT OUTER JOIN FETCH operators1.operators operators2
LEFT OUTER JOIN FETCH operators1.networkCodes
WHERE domain.domainId = :domainId
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
24535 次 |
| 最近记录: |