您的位置:首页 > Web前端

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

2011-11-05 17:08 483 查看
(总结在后面)

通过子查询预抓取集合:

view
plaincopy
to clipboardprint?

<set
fetch="subselect" ..>

@org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)

配置文件:

view
plaincopy
to clipboardprint?

<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>

测试代码:

view
plaincopy
to clipboardprint?

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();

}

通过联结即时抓取:



view
plaincopy
to clipboardprint?

<set
fetch="join" ..>

@org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.JOIN)

配置文件:

view
plaincopy
to clipboardprint?

<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的错误,那么肯定就是采用的懒加载的方式

view
plaincopy
to clipboardprint?

/**

* 前提是我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中,如何生效呢?呵呵

view
plaincopy
to clipboardprint?

/**

* 前提是我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:

view
plaincopy
to clipboardprint?

@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>();

.....

调用:

执行了查询集合数据

view
plaincopy
to clipboardprint?

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数据):

view
plaincopy
to clipboardprint?

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该如何呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: