(总结在后面)
通过子查询预抓取集合:
配置文件:
测试代码:
通过联结即时抓取:
配置文件:
测试代码:
很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式
换个版本(hibernate-distribution-3.6.4.Final):
还是这样。
突然明白过来,他在你指定的HQL中,如何生效呢?呵呵
JPA:
调用:
执行了查询集合数据
上面这样就生效了。看来fetch方式如此不堪。
##总结:##
JPA使用下面代码测试(前提是有三条Item,一条没有Bid数据):
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该如何呢?
通过子查询预抓取集合:
- <set fetch="subselect" ..>
- @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
配置文件:
- <class name="Item" table="ITEM">
- <id name="itemId" column="ITEM_ID" type="integer">
- <generator class="native"/>
- </id>
- <property name="itemName" type="string" column="ITEM_NAME"/>
- <bag name="bids" inverse="true" cascade="save-update" fetch="subselect">
- <key column="ITEM_ID_M"></key>
- <one-to-many class="Bid"/>
- </bag>
- </class>
测试代码:
- private static void select() {
- Configuration configuration = new Configuration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Item item = (Item) session.get(Item.class, 1);
- System.out.println("-----");
- Collection<Bid> bids = item.getBids();
- System.out.println("+++++");
- for(Iterator it = bids.iterator();it.hasNext();){
- Bid bid = (Bid) it.next();
- System.out.println(bid);
- }
- // hibernate打印:
- // Hibernate: select item0_.ITEM_ID as ITEM1_1_0_, item0_.ITEM_NAME as ITEM2_1_0_ from ITEM item0_ where item0_.ITEM_ID=?
- // -----
- // +++++
- // 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=?
- // Bid [bidId=1, bidMoeny=12.0]
- // Bid [bidId=2, bidMoeny=13.0]
- //如果是多条就会变成:
- //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_)
- session.close();
- sessionFactory.close();
- }
通过联结即时抓取:
- <set fetch="join" ..>
- @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.JOIN)
配置文件:
- <class name="Item" table="ITEM">
- <id name="itemId" column="ITEM_ID" type="integer">
- <generator class="native"/>
- </id>
- <property name="itemName" type="string" column="ITEM_NAME"/>
- <set name="bids" inverse="true" cascade="save-update" fetch="join">
- <key column="ITEM_ID_M"></key>
- <one-to-many class="Bid"/>
- </set>
- </class>
测试代码:
很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式
- /**
- * 前提是我Item有三条数据,两条没有Bid
- */
- private static void select() {
- Configuration configuration = new Configuration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Query query = session.createQuery("select o from Item o");
- List<Item> items = query.list();
- System.out.println(items.size());
- for(int i=0;i<items.size();i++){
- Item item = items.get(i);
- System.out.println(item.getBids());
- }
- // 后台打印:
- // Hibernate: select item0_.ITEM_ID as ITEM1_1_, item0_.ITEM_NAME as ITEM2_1_ from ITEM item0_
- // 3
- // 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=?
- // [Bid [bidId=2, bidMoeny=12.0], Bid [bidId=1, bidMoeny=13.0]]
- // 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=?
- // []
- // 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=?
- // []
- // 很奇怪,不解,难道我这个版本的hibernate有bug?把session.close();放在获取之前就会报no session的错误,那么肯定就是采用的懒加载的方式
- session.close();
- sessionFactory.close();
- }
换个版本(hibernate-distribution-3.6.4.Final):
还是这样。
突然明白过来,他在你指定的HQL中,如何生效呢?呵呵
- /**
- * 前提是我Item有三条数据,两条没有Bid
- */
- private static void select2() {
- Configuration configuration = new Configuration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Item item = (Item) session.get(Item.class, 1);
- // 打印:
- // 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=?
- session.close();
- sessionFactory.close();
- }
JPA:
- @Entity
- public class Item implements Serializable {
- @Id
- @GeneratedValue
- @Column(name="ITEM_ID")
- private Integer itemId;
- @Column(name="ITEM_NAME")
- private String itemName;
- @OneToMany(mappedBy="item",cascade=CascadeType.ALL)
- @Fetch(value=FetchMode.JOIN)
- private Set<Bid> bids = new HashSet<Bid>();
- .....
调用:
执行了查询集合数据
- private static void select() {
- EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
- EntityManager em = factory.createEntityManager();
- Query query = em.createQuery("select o from Item o ");
- List<Item> items = query.getResultList();
- // 后台打印:
- // 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=?
- // 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=?
- em.close();
- factory.close();
- }
- private static void select2() {
- EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
- EntityManager em = factory.createEntityManager();
- Item item = em.find(Item.class, 1);
- System.out.println("----");
- System.out.println(item.getBids());
- // 后台打印:
- // 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=?
- // ----
- // [Bid [bidId=1, bidMoeny=12.0], Bid [bidId=2, bidMoeny=13.0]]
- //但是,我们是三条数据,一条Item没有Bid,所以出问题了
- em.close();
- factory.close();
- }
上面这样就生效了。看来fetch方式如此不堪。
##总结:##
JPA使用下面代码测试(前提是有三条Item,一条没有Bid数据):
- private static void select() {
- EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
- EntityManager em = factory.createEntityManager();
- Query query = em.createQuery("select o from Item o ");
- List<Item> items = query.getResultList();
- em.close();
- factory.close();
- }
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该如何呢?