关于jpa / hibernate子选择提取

时间:2017-03-29 12:10:58

标签: java sql hibernate jpa sql-subselect

我对代码片段(full source code)进行了询问,这是一本关于Hibernate / JPA的书的附带代码示例。

以下是代码清单:

public class Subselect extends JPATest {

    @Override
    public void configurePersistenceUnit() throws Exception {
        configurePersistenceUnit("FetchingSubselectPU");
    }

    public FetchTestData storeTestData() throws Exception {
        UserTransaction tx = TM.getUserTransaction();
        tx.begin();
        EntityManager em = JPA.createEntityManager();

        Long[] itemIds = new Long[3];
        Long[] userIds = new Long[3];

        User johndoe = new User("johndoe");
        em.persist(johndoe);
        userIds[0] = johndoe.getId();

        User janeroe = new User("janeroe");
        em.persist(janeroe);
        userIds[1] = janeroe.getId();

        User robertdoe = new User("robertdoe");
        em.persist(robertdoe);
        userIds[2] = robertdoe.getId();

        Item item = new Item("Item One", CalendarUtil.TOMORROW.getTime(), johndoe);
        em.persist(item);
        itemIds[0] = item.getId();
        for (int i = 1; i <= 3; i++) {
            Bid bid = new Bid(item, robertdoe, new BigDecimal(9 + i));
            item.getBids().add(bid);
            em.persist(bid);
        }

        item = new Item("Item Two", CalendarUtil.TOMORROW.getTime(), johndoe);
        em.persist(item);
        itemIds[1] = item.getId();
        for (int i = 1; i <= 1; i++) {
            Bid bid = new Bid(item, janeroe, new BigDecimal(2 + i));
            item.getBids().add(bid);
            em.persist(bid);
        }

        item = new Item("Item Three", CalendarUtil.AFTER_TOMORROW.getTime(), janeroe);
        em.persist(item);
        itemIds[2] = item.getId();
        for (int i = 1; i <= 1; i++) {
            Bid bid = new Bid(item, johndoe, new BigDecimal(3 + i));
            item.getBids().add(bid);
            em.persist(bid);
        }

        tx.commit();
        em.close();

        FetchTestData testData = new FetchTestData();
        testData.items = new TestData(itemIds);
        testData.users = new TestData(userIds);
        return testData;
    }

    @Test
    public void fetchCollectionSubselect() throws Exception {
        storeTestData();

        UserTransaction tx = TM.getUserTransaction();
        try {
            tx.begin();
            EntityManager em = JPA.createEntityManager();

            List<Item> items = em.createQuery("select i from Item i").getResultList();
            // select * from ITEM

            for (Item item : items) {
                assertTrue(item.getBids().size() > 0);
                // select * from BID where ITEM_ID in (
                //  select ID from ITEM
                // )
            }

            // The actual test
            em.clear();
            items = em.createQuery("select i from Item i").getResultList();
            // Access should load all collections
            assertTrue(items.iterator().next().getBids().size() > 0);
            em.clear(); // Detach all
            for (Item item : items) {
                assertTrue(item.getBids().size() > 0);
            }

            tx.commit();
            em.close();
        } finally {
            TM.rollback();
        }
    }

}

我不明白的具体部分是这一部分:

for (Item item : items) {
    assertTrue(item.getBids().size() > 0);
    // select * from BID where ITEM_ID in (
    //  select ID from ITEM
    // )
}

它旨在演示如何使用预取hibernate的子选择功能以及将要执行的SQL查询。

以下注释:// select ID from ITEM表示从数据库中检索所有项目ID。这是subselect prefetching的意思吗?为什么要从ID表中检索所有ITEM

以下是Item实体:

@Entity
public class Item {
 @OneToMany(mappedBy = "item")
 @org.hibernate.annotations.Fetch(
 org.hibernate.annotations.FetchMode.SUBSELECT
 )
 protected Set<Bid> bids = new HashSet<>();
 // ...
}

1 个答案:

答案 0 :(得分:2)

子选择预取意味着用于加载父项的原始查询在加载关联子项时用作子查询,以便所有加载父项中的子项一次初始化。您加载父项的查询是select i from Item i(您加载所有项目),因此它被用作出价的子查询(转换为仅投影项目的ID)。

如果您的原始查询为select i from Item i where i.someProperty = :something,则加载出价时的子查询将为select ID from ITEM where SOME_PROPERTY_COLUMN = :something