After reading all of "Java Persistence with Hibernate", reading the relevant chapters over and over again, searching online and through these posts, and trying all sorts of permutations on this, I'm convinced this is just a fundamental misunderstanding on my part, but anything you may be able to clear up will be greatly appreciated.
I have a one-to-one association between two classes. When I create a Query or Criteria on one of these classes with a FetchMode.JOIN on the other, my expectation when calling criteria.list() is that a single SQL statement against the database will be created, so that both the class and its association are loaded at once, with no further hits against db.
Instead, I see what looks like to me as an N+1 issue. That is, a single SQL query that appears to capture all the information for a list of both classes is run. Then, apparently redundantly, a whole series of identical one-row SQL queries get run, containing what appears to be a subset of the same information that the 1st query returns!
My goal is to get this so that only 1 query runs, to minimize database hit when retrieving lists of pre-initialized objects.
I've pared it down to the simplest case between two classes, which is why I think I must be missing something in understanding. Please see details below.
This post seems to be the same issue:
http://forum.hibernate.org/viewtopic.ph ... +redundant
If I find the answer myself, I'll be sure to update this post. But, I'd would definitely appreciate any help, as I've been banging my head against this one awhile.
Hibernate version:3.2.5
Mapping documents:
Class One, with a one-to-one association to class Two
Code:
@Entity
@Table(name="HTEST_ONE")
public class One
{
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
protected Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn
private Two two;
@XmlTransient
public Two getTwo()
{
return two;
}
public void setTwo(Two two)
{
this.two = two;
}
}
Code:
@Entity
@Table(name="HTEST_TWO")
public class Two
{
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
protected Long id;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "two")
protected One one;
@XmlTransient
public One getOne()
{
return one;
}
public void setOne(One one)
{
this.one = one;
}
}
Code between sessionFactory.openSession() and session.close():Code:
Criteria criteria = session.createCriteria(One.class)
.setComment("criteria: simple")
.createAlias("two","t", CriteriaSpecification.INNER_JOIN)
.setFetchMode("t", FetchMode.JOIN)
;
list = (List<One>) criteria.list();
Full stack trace of any exception that occurs:
No exceptions. Trying to optimize.
Name and version of the database you are using:
Oracle 11g
The generated SQL (show_sql=true):
/* criteria query: This gets run once */
select
this_.id as id4_1_,
this_.two_id as two2_4_1_,
t1_.id as id5_0_
from
HTEST_ONE this_,
HTEST_TWO t1_
where
this_.two_id=t1_.id
/* load hibernatebear.One -- After the above, this gets run immediately...
This query gets run many times, seeming like an N+1 problem. */
select
one0_.id as id4_0_,
one0_.two_id as two2_4_0_
from
HTEST_ONE one0_
where
one0_.two_id=?
All this happens before the Java code excerpted above (in "Code between sessionFactory.openSession() and session.close()") returns.
Debug level Hibernate log excerpt:
(for completeness, just an excerpt...)
16:01:46,323 INFO main MultiuseDao:15 - Creating HibernateTemplate
16:01:46,448 DEBUG main ConnectionManager:421 - opening JDBC connection
16:01:46,448 DEBUG main AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:01:46,463 DEBUG main SQL:401 -
/* criteria: simple */ /* criteria query */ select
this_.id as id4_1_,
this_.two_id as two2_4_1_,
t1_.id as id5_0_
from
HTEST_ONE this_,
HTEST_TWO t1_
where
this_.two_id=t1_.id
16:01:46,604 DEBUG main AbstractBatcher:382 - about to open ResultSet (open ResultSets: 0, globally: 0)
16:01:46,682 DEBUG main AbstractBatcher:389 - about to close ResultSet (open ResultSets: 1, globally: 1)
16:01:46,682 DEBUG main AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:01:46,682 DEBUG main AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:01:46,682 DEBUG main SQL:401 -
/* load hibernatebear.One */ select
one0_.id as id4_0_,
one0_.two_id as two2_4_0_
from
HTEST_ONE one0_
where
one0_.two_id=?
16:01:46,713 DEBUG main AbstractBatcher:382 - about to open ResultSet (open ResultSets: 0, globally: 0)
16:01:46,713 DEBUG main AbstractBatcher:389 - about to close ResultSet (open ResultSets: 1, globally: 1)
16:01:46,713 DEBUG main AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:01:46,713 DEBUG main AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:01:46,713 DEBUG main SQL:401 -
/* load hibernatebear.One */ select
one0_.id as id4_0_,
one0_.two_id as two2_4_0_
from
HTEST_ONE one0_
where
one0_.two_id=?
16:01:46,760 DEBUG main AbstractBatcher:382 - about to open ResultSet (open ResultSets: 0, globally: 0)
16:01:46,760 DEBUG main AbstractBatcher:389 - about to close ResultSet (open ResultSets: 1, globally: 1)
16:01:46,760 DEBUG main AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:01:46,760 DEBUG main AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:01:46,760 DEBUG main SQL:401 -
/* load hibernatebear.One */ select
one0_.id as id4_0_,
one0_.two_id as two2_4_0_
from
HTEST_ONE one0_
where
one0_.two_id=?
16:01:46,791 DEBUG main AbstractBatcher:382 - about to open ResultSet (open ResultSets: 0, globally: 0)
16:01:46,791 DEBUG main AbstractBatcher:389 - about to close ResultSet (open ResultSets: 1, globally: 1)
16:01:46,791 DEBUG main AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:01:46,791 DEBUG main AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:01:46,791 DEBUG main SQL:401 -
/* load hibernatebear.One */ select
one0_.id as id4_0_,
one0_.two_id as two2_4_0_
from
HTEST_ONE one0_
where
one0_.two_id=?
16:01:46,823 DEBUG main AbstractBatcher:382 - about to open ResultSet (open ResultSets: 0, globally: 0)
16:01:46,823 DEBUG main AbstractBatcher:389 - about to close ResultSet (open ResultSets: 1, globally: 1)
16:01:46,823 DEBUG main AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:01:46,823 DEBUG main AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:01:46,823 DEBUG main SQL:401 -
/* load hibernatebear.One */ select
one0_.id as id4_0_,
one0_.two_id as two2_4_0_
from
HTEST_ONE one0_
where
one0_.two_id=?