hibernate 通过子查询预抓取集合 fetch subselect join (最后遗留疑问)

(总结在后面)
通过子查询预抓取集合:
  1. <set fetch="subselect"..>
  2. @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)

配置文件:
  1. <classname="Item"table="ITEM">
  2. <id name="itemId"column="ITEM_ID"type="integer">
  3. <generatorclass="native"/>
  4. </id>
  5. <property name="itemName"type="string"column="ITEM_NAME"/>
  6. <bag name="bids"inverse="true"cascade="save-update"fetch="subselect">
  7. <key column="ITEM_ID_M"></key>
  8. <one-to-manyclass="Bid"/>
  9. </bag>
  10. </class>

测试代码:
  1. privatestaticvoidselect() {
  2. Configuration configuration =newConfiguration().configure();
  3. SessionFactory sessionFactory = configuration.buildSessionFactory();
  4. Session session = sessionFactory.openSession();
  5. Item item = (Item) session.get(Item.class,1);
  6. System.out.println("-----");
  7. Collection<Bid> bids = item.getBids();
  8. System.out.println("+++++");
  9. for(Iterator it = bids.iterator();it.hasNext();){
  10. Bid bid = (Bid) it.next();
  11. System.out.println(bid);
  12. }
  13. //hibernate打印:
  14. //Hibernate: select item0_.ITEM_ID as ITEM1_1_0_, item0_.ITEM_NAME as ITEM2_1_0_ from ITEM item0_ where item0_.ITEM_ID=?
  15. //-----
  16. //+++++
  17. //Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?
  18. //Bid [bidId=1, bidMoeny=12.0]
  19. //Bid [bidId=2, bidMoeny=13.0]
  20. //如果是多条就会变成:
  21. //Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M in (select item0_.ITEM_ID from ITEM item0_)
  22. session.close();
  23. sessionFactory.close();
  24. }






通过联结即时抓取:
  1. <set fetch="join"..>
  2. @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.JOIN)


配置文件:
  1. <classname="Item"table="ITEM">
  2. <id name="itemId"column="ITEM_ID"type="integer">
  3. <generatorclass="native"/>
  4. </id>
  5. <property name="itemName"type="string"column="ITEM_NAME"/>
  6. <set name="bids"inverse="true"cascade="save-update"fetch="join">
  7. <key column="ITEM_ID_M"></key>
  8. <one-to-manyclass="Bid"/>
  9. </set>
  10. </class>

测试代码:
很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式
  1. /**
  2. * 前提是我Item有三条数据,两条没有Bid
  3. */
  4. privatestaticvoidselect() {
  5. Configuration configuration =newConfiguration().configure();
  6. SessionFactory sessionFactory = configuration.buildSessionFactory();
  7. Session session = sessionFactory.openSession();
  8. Query query = session.createQuery("select o from Item o");
  9. List<Item> items = query.list();
  10. System.out.println(items.size());
  11. for(inti=0;i<items.size();i++){
  12. Item item = items.get(i);
  13. System.out.println(item.getBids());
  14. }
  15. //后台打印:
  16. //Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from ITEM item0_
  17. //3
  18. //Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?
  19. //[Bid [bidId=2, bidMoeny=12.0], Bid [bidId=1, bidMoeny=13.0]]
  20. //Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?
  21. //[]
  22. //Hibernate: select bids0_.ITEM_ID_M as ITEM3_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.bidMoeny as bidMoeny0_0_, bids0_.ITEM_ID_M as ITEM3_0_0_ from BID bids0_ where bids0_.ITEM_ID_M=?
  23. //[]
  24. //很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式
  25. session.close();
  26. sessionFactory.close();
  27. }


换个版本(hibernate-distribution-3.6.4.Final):
还是这样。
突然明白过来,他在你指定的HQL中,如何生效呢?呵呵
  1. /**
  2. * 前提是我Item有三条数据,两条没有Bid
  3. */
  4. privatestaticvoidselect2() {
  5. Configuration configuration =newConfiguration().configure();
  6. SessionFactory sessionFactory = configuration.buildSessionFactory();
  7. Session session = sessionFactory.openSession();
  8. Item item = (Item) session.get(Item.class,1);
  9. //打印:
  10. //Hibernate: select item0_.ITEM_ID as ITEM1_1_1_, item0_.ITEM_NAME as ITEM2_1_1_, bids1_.ITEM_ID_M as ITEM3_1_3_, bids1_.BID_ID as BID1_3_, bids1_.BID_ID as BID1_0_0_, bids1_.bidMoeny as bidMoeny0_0_, bids1_.ITEM_ID_M as ITEM3_0_0_ from ITEM item0_ left outer join BID bids1_ on item0_.ITEM_ID=bids1_.ITEM_ID_M where item0_.ITEM_ID=?
  11. session.close();
  12. sessionFactory.close();
  13. }


JPA:
  1. @Entity
  2. publicclassItemimplementsSerializable {
  3. @Id
  4. @GeneratedValue
  5. @Column(name="ITEM_ID")
  6. privateInteger itemId;
  7. @Column(name="ITEM_NAME")
  8. privateString itemName;
  9. @OneToMany(mappedBy="item",cascade=CascadeType.ALL)
  10. @Fetch(value=FetchMode.JOIN)
  11. privateSet<Bid> bids =newHashSet<Bid>();
  12. .....

调用:
执行了查询集合数据
  1. privatestaticvoidselect() {
  2. EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
  3. EntityManager em = factory.createEntityManager();
  4. Query query = em.createQuery("select o from Item o ");
  5. List<Item> items = query.getResultList();
  6. //后台打印:
  7. //Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from Item item0_
  8. //Hibernate: select bids0_.ITEM_ID as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.BID_MONEY as BID2_0_0_, bids0_.ITEM_ID as ITEM3_0_0_ from Bid bids0_ where bids0_.ITEM_ID=?
  9. //Hibernate: select bids0_.ITEM_ID as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.BID_MONEY as BID2_0_0_, bids0_.ITEM_ID as ITEM3_0_0_ from Bid bids0_ where bids0_.ITEM_ID=?
  10. em.close();
  11. factory.close();
  12. }
  13. privatestaticvoidselect2() {
  14. EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
  15. EntityManager em = factory.createEntityManager();
  16. Item item = em.find(Item.class,1);
  17. System.out.println("----");
  18. System.out.println(item.getBids());
  19. //后台打印:
  20. //Hibernate: select item0_.ITEM_ID as ITEM1_0_1_, item0_.ITEM_NAME as ITEM2_0_1_, bids1_.ITEM_ID as ITEM3_0_3_, bids1_.BID_ID as BID1_3_, bids1_.BID_ID as BID1_1_0_, bids1_.BID_MONEY as BID2_1_0_, bids1_.ITEM_ID as ITEM3_1_0_ from Item item0_ left outer join Bid bids1_ on item0_.ITEM_ID=bids1_.ITEM_ID where item0_.ITEM_ID=?
  21. //----
  22. //[Bid [bidId=1, bidMoeny=12.0], Bid [bidId=2, bidMoeny=13.0]]
  23. //但是,我们是三条数据,一条Item没有Bid,所以出问题了
  24. em.close();
  25. factory.close();
  26. }


上面这样就生效了。看来fetch方式如此不堪。
##总结:##

JPA使用下面代码测试(前提是有三条Item,一条没有Bid数据):
  1. privatestaticvoidselect() {
  2. EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
  3. EntityManager em = factory.createEntityManager();
  4. Query query = em.createQuery("select o from Item o ");
  5. List<Item> items = query.getResultList();
  6. em.close();
  7. factory.close();
  8. }


join:
1、无论使用hibernate和jpa使用HQL或者QL语句,是不生效的。
2、区别在于JPA:
@OneToMany(mappedBy="item",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@Fetch(value=FetchMode.JOIN)
后台打印:
Hibernate: select item0_.ITEM_ID as ITEM1_0_, item0_.ITEM_NAME as ITEM2_0_ from Item item0_
Hibernate: select bids0_.ITEM_ID as ITEM3_0_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_1_0_, bids0_.BID_MONEY as BID2_1_0_, bids0_.ITEM_ID as ITEM3_1_0_ from Bid bids0_ where bids0_.ITEM_ID=?
Hibernate: select bids0_.ITEM_ID as ITEM3_0_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_1_0_, bids0_.BID_MONEY as BID2_1_0_, bids0_.ITEM_ID as ITEM3_1_0_ from Bid bids0_ where bids0_.ITEM_ID=?
Hibernate: select bids0_.ITEM_ID as ITEM3_0_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_1_0_, bids0_.BID_MONEY as BID2_1_0_, bids0_.ITEM_ID as ITEM3_1_0_ from Bid bids0_ where bids0_.ITEM_ID=?
像这样,无论,JPA中你是否指明了懒加载,只要生命了fetch=join方式,就会变成立即加载。

Hibernate不会,hibernate始终就是默认就是把返回代理放在最优先考虑的方式。
3、如果使用非HQL或QL的查询方式,如get之类的,JOIN就会出现问题,因为使用的left outer join方式,就只会查询出有关联数据的Item。


SUBSELECT:
1、JPA和hibernate是相同的:
@OneToMany(mappedBy="item",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@Fetch(value=FetchMode.SUBSELECT)
就是,默认是懒加载模式
后台打印:
Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from Item item0_

2、但是,如果修改为:
@OneToMany(mappedBy="item",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@Fetch(value=FetchMode.SUBSELECT)
后台就会打印:
Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from Item item0_
Hibernate: select bids0_.ITEM_ID as ITEM3_1_1_, bids0_.BID_ID as BID1_1_, bids0_.BID_ID as BID1_0_0_, bids0_.BID_MONEY as BID2_0_0_, bids0_.ITEM_ID as ITEM3_0_0_ from Bid bids0_ where bids0_.ITEM_ID in (select item0_.ITEM_ID from Item item0_)
就是JPA中QL语句也会生效SUBSELECT设置。Hibernate也会生效。



所以,综上所述,当时使用HQL或QL查询的时候,而且需要获取脱管对象的关联对象时,建议使用SUBSELECT方式,但是,还需要额外指明即时加载。且,JPA的JOIN方式的QL查询还存在bug。



但是,我们如果想在第一个select的HQL方式中也用join该如何呢?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值