There could be a scenario wherein we need an association to be always available whenever an Entity is loaded. In this case the additional select queries that are fired are a performance loss. We could tell Hibernate to fetch the entity and the association in a single call to the database.
Consider the case where we need all the Shelf and its books to be always available. One way to do this would be to change our fetch strategy for the Book set in Shelf to join.
I executed a list query to fetch multiple Shelves.
Consider the case where we need all the Shelf and its books to be always available. One way to do this would be to change our fetch strategy for the Book set in Shelf to join.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.collection.smart"> <class name="Shelf" table="SHELF"> <id name="id" type="integer"> <column name="ID" /> <generator class="native" /> </id> <property name="code" type="string"> <column name="CODE" length="50" not-null="true" /> </property> <set name="allBooks" cascade="all-delete-orphan" inverse="true"
fetch="join" > <key column="SHELF_ID" not-null="true" /> <one-to-many class="Book" /> </set> </class> </hibernate-mapping>If were to load a specific shelf as in the below code:
public static void testJoinedLoad() { Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Shelf shelf = (Shelf) session.load(Shelf.class, 1);
System.out.println("shelf class is " + shelf.getClass() + " and set class is " + shelf.getAllBooks().getClass()); System.out.println("shelf is " + shelf.getCode() + " and book count is "
+ shelf.getAllBooks().size());
transaction.commit();
session.close();
}
The SQL logs are as below:Hibernate:
/* load com.collection.smart.Shelf */
select
shelf0_.ID as ID1_1_,
shelf0_.CODE as CODE1_1_,
allbooks1_.SHELF_ID as SHELF3_3_,
allbooks1_.ID as ID3_,
allbooks1_.ID as ID0_0_,
allbooks1_.Name as Name0_0_,
allbooks1_.shelf_id as shelf3_0_0_
from
SHELF shelf0_
left outer join
BOOK allbooks1_
on shelf0_.ID=allbooks1_.SHELF_ID
where
shelf0_.ID=?
shelf class is class com.collection.smart.Shelf$$EnhancerByCGLIB$$c94b6717 and s et class is class org.hibernate.collection.PersistentSet shelf is SH001 and book count is 2As seen Hibernate loads the shelf and all the books on it.
I executed a list query to fetch multiple Shelves.
public static void testJoinedLoad() { Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); System.out.println("Testing Query select"); session = sessionFactory.openSession(); transaction = session.beginTransaction(); @SuppressWarnings("unchecked") List<Shelf> shelfs = session.createCriteria(Shelf.class)
.add(Restrictions.le("id", 3)).list(); for (Shelf shelf : shelfs) { System.out.println("shelf class is " + shelf.getClass()); Set<Book> books = shelf.getAllBooks(); System.out.println("The Collection class is " + shelf.getAllBooks().getClass()); System.out.println("Total books is " + books.size()); } transaction.commit(); session.close(); }The SQL logs are as below:
Testing Query select
Hibernate:
/* criteria query */
select
this_.ID as ID1_1_,
this_.CODE as CODE1_1_,
allbooks2_.SHELF_ID as SHELF3_3_,
allbooks2_.ID as ID3_,
allbooks2_.ID as ID0_0_,
allbooks2_.Name as Name0_0_,
allbooks2_.shelf_id as shelf3_0_0_
from
SHELF this_
left outer join
BOOK allbooks2_
on this_.ID=allbooks2_.SHELF_ID
where
this_.ID<=?
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Total books is 2
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Total books is 2
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Total books is 1
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Total books is 1
As can be seen the entire result set was fetched in a single query for the criteria. I then executed the same query using an equivalent HQL base code (like the previous example):public static void testJoinedLoad() { Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); System.out.println("Testing Query select"); session = sessionFactory.openSession(); transaction = session.beginTransaction(); @SuppressWarnings("unchecked") List<Shelf> shelfs = session.createQuery("from Shelf shelf where shelf.id <= 3 ")
.list();
for (Shelf shelf : shelfs) {
System.out.println("shelf class is " + shelf.getClass());
Set<Book> books = shelf.getAllBooks();
System.out.println("The Collection class is " + shelf.getAllBooks().getClass());
System.out.println("Total books is " + books.size());
}
transaction.commit();
session.close();
}
The SQL logs are as below:Testing Query select
Hibernate:
/*
from
Shelf shelf
where
shelf.id <= 3 */
select
shelf0_.ID as ID1_,
shelf0_.CODE as CODE1_
from
SHELF shelf0_
where
shelf0_.ID<=3
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Hibernate:
/* load one-to-many com.collection.smart.Shelf.allBooks */
select
allbooks0_.SHELF_ID as SHELF3_1_,
allbooks0_.ID as ID1_,
allbooks0_.ID as ID0_0_,
allbooks0_.Name as Name0_0_,
allbooks0_.shelf_id as shelf3_0_0_
from
BOOK allbooks0_
where
allbooks0_.SHELF_ID=?
Total books is 2
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Hibernate:
/* load one-to-many com.collection.smart.Shelf.allBooks */
select
allbooks0_.SHELF_ID as SHELF3_1_,
allbooks0_.ID as ID1_,
allbooks0_.ID as ID0_0_,
allbooks0_.Name as Name0_0_,
allbooks0_.shelf_id as shelf3_0_0_
from
BOOK allbooks0_
where
allbooks0_.SHELF_ID=?
Total books is 1
shelf class is class com.collection.smart.Shelf
The Collection class is class org.hibernate.collection.PersistentSet
Hibernate:
/* load one-to-many com.collection.smart.Shelf.allBooks */
select
allbooks0_.SHELF_ID as SHELF3_1_,
allbooks0_.ID as ID1_,
allbooks0_.ID as ID0_0_,
allbooks0_.Name as Name0_0_,
allbooks0_.shelf_id as shelf3_0_0_
from
BOOK allbooks0_
where
allbooks0_.SHELF_ID=?
Total books is 1
In this case the join strategy has not been used. The behaviour is same as that seen in a fetch=select strategy. This is because HQL does not respect the join fetching strategy specified in the mappings unlike the Criteria code.
No comments:
Post a Comment