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 1As 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 1In 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