如果我遇到n + 1问题的情况我通常使用JPA“join fetch”关键字,如果它只是一个间接(即从Person p join fetch p.address中选择p)或者它是不止一个间接我使用JPA提供程序专有的查询提示,在我的情况下是eclipselink(即从查询提示eclipselink.join-fetch = p.address.city的人中选择p)。这在文章Java Persistence Performance中得到了很好的解释。
无论如何,最近我偶然发现了一个数据模型,其中两个实体被另一个实体子类化。
我有Account
拥有Contact
。联系人本身是一个抽象的超类,它由Person
或Company
扩展。并且一个人确实与Hobby
的列表有关系。
@Entity
public class Account
{
@OneToOne
private Contact contact;
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Contact {}
@Entity
public class Person extends Contact
{
@OneToMany
private List<Hobby> hobbies;
}
@Entity
public class Company extends Contact {}
我需要加载一个帐户列表select a from Account a
。由于兴趣爱好,我肯定遇到了n + 1问题。没问题,我想,通过上面提到的两个探讨良好的解决方案,我可以解决n + 1问题。但很快我意识到这不起作用。
select a from Account a join fetch a.contacts
无法获取兴趣爱好。查询提示select a from Account a
eclipselink.join-fetch=a.contacts
也不行。查询提示select a from Account a
的{{1}}会抛出一个。{1}}
eclipselink.join-fetch=a.contacts.hobbies
- 异常
我也试过使用JPA治疗功能i。即... navigated to a non-existent relationship
,但这不会带来爱好,只能吸引人而非公司。
有没有人知道如何使用join fetch或eclipselink查询提示来完成这样的查询优化?
修改
为了回答克里斯的评论。
业余爱好中的select a from Account a join fetch treat(a.contact as Person) p join fetch p.hobbies
注释对查询没有任何影响。没有它的查询没有区别。
以下是每个查询使用@BatchFetch注释生成的sqls
@BatchFetch
select a from Account a
1 SELECT id, contact_id FROM account
2 SELECT DISTINCT DTYPE FROM contact WHERE (ID = ?)
3 SELECT t0.ID, t0.DTYPE, t1.ID, t1.FOUNDED FROM contact t0, company t1 WHERE ((t0.ID = ?) AND ((t1.ID = t0.ID) AND t0.DTYPE = ?))
4 SELECT DISTINCT DTYPE FROM contact WHERE (ID = ?)
5 SELECT t0.ID, t0.DTYPE, t1.ID, t1.NAME FROM contact t0, person t1 WHERE ((t0.ID = ?) AND ((t1.ID = t0.ID) AND (t0.DTYPE = ?)))
6 SELECT ID, OUTDOOR, PERSON_ID FROM hobby WHERE (PERSON_ID = ?)
... (repetition of lines 2 to 6)
select a from Account a join fetch a.contacts