随笔-95  评论-31  文章-10  trackbacks-0
JPA
要想彻底解决1+N的问题,即查询one的时候级联出many,多出N个select语句。

1:加Fetch=FetchType.Lazy没用,这个只能缓解,但是使用的时候即one.many.iterator()的时候还是会发送N条select语句
2:加@Fetch(JOIN)也没用,这个属于Hibernate提供的注解, 调用entityManager.find()或者自定义createQuery(jpql),虽然会使用外连接,但是一旦调用one.many.iterator的时候 还是避免不了发送select语句,除非jpql里面避免实体的查询,只查询实体属性值,即返回值是个Object[],这样可避免,因为没有机会调用one.many.iterator方法,都是实体属性值。

最终解决方法是: jpql调用left/right/inner join fetch语句,主要是加fetch,不加效果仍然一样,这样即可避免调用one.many.iterator时发送N条select语句,只有一条外连接语句,它会无视FetchType属性Lazy还是eager。

示例: A---->B  @oneToMany   A1 B多

 1 //示意代码
 2 public class A{
 3 @OneToMany(cascade={CascadeType.All},fetch=FetchType.Lazy,mappedBy="a")
    //mappedBy表示当前实体不维护外键,外键在多的一方维护,即保存B的时候会保存A,也可设置为允许为null

 4 private Set<B> bSet;
 5 
 6 }
 7 @Test
 8 public void test(){
 9       //最常见方式 
10       //第一种
11       A a = entityManager.find(A.class,1L);
12       a.bSet.iterator();//触发N条select语句
13 
14       //第二种
15       Query query = entityManager.createQuery(select a from A a );     
16       List<A> aList = query.getResultList();
17       aList.get(0).bSet.iterator();//触发N条select语句
18 
19       //第三种
20       Query query = entityManager.createQuery(select a from A a left join a.bSet b where a.id=?1);
21       List<A> aList = query.getResultList();
22       aList.get(0).bSet.iterator();//触发N条select语句
23       
24       //第四种
25       Query query = entityManager.createQuery(select a.name,b.name from A a left join a.bSet b where a.id=?1);
26       List
<Object[]> aList=query.getResultList(); //返回值是数组,即是a.name和b.name没有地方触发N条select语句
27    
28       //第五种
29       Query query = entityManager.createQuery(select a,b.name,b.id from A a left join a.bSet b where a.id=?1);
30       List
<Object[]> aList=query.getResultList(); //返回值是数组,即a实体和b.name,b.id
31       (A)(aList.get(0)[0]).bSet.iterator()//触发N条select语句。
32 
33       //第六种
34       Query query = entityManager.createQuery(select a from A a left join fetch a.bSet b where a.id=?1);
35       List<A> aList = query.getResultList();
36       aList.get(0).bSet.iterator();//不会触发N条select语句
37       //这里比第五种只多加了个fetch,就不会出现N条select语句
38                
39 }


理论上JPA实体只要映射好关系,A--->B--->C--->D....... 只需from A 即可查询出B C D, 但这样做会影响性能,因为实际中我们可能只需要不同表的若干属性,而不是全部,所以首先有了LAZY,但是它只能缓解,真正使用的时候还是会触发N条select语句,所以我们又希望一条join语句搞定,一般情况下,只需要使用left/right/inner join 即可,不需要加fetch,前提是select后面跟的是实体属性而不是实体,而一旦跟上实体,那么由该实体获取多的一方数据时,仍然会触发N条select语句,这个时候就要强制加上xxxx join fetch即可避免。

所以想避免one.many.iterator获取多的一方数据触发N条select语句,那么只有两种办法
1: select 后面跟实体属性,不要跟实体, 再使用join。
2: 如果select 后面一定要跟实体,那么使用xxxx join fetch,这样即使one.many.iterator的时候也不会触发N条select语句。


posted on 2015-07-20 17:04 朔望魔刃 阅读(324) 评论(0)  编辑  收藏 所属分类: java

只有注册用户登录后才能发表评论。


网站导航: