开发者

Collection being eagerly loaded, even though lazy = true?

I am running through a problem regarding Hibernate lazy loading. I posted this on Hibernate Forum but received no answer, so I thought that perhaps you guys here on stackoverflow could give me a hand. The post link is : https://forum.hibernate.org/viewtopic.php?f=1&t=1012419 I am copying the content below, thanks in advance:

The problem is that I am trying to lazy load a collection, but it gets eagerly loaded all the time, making a huge impact on my app performance. Here it´s the scenario, I describe the model for the 3 classes involved:

Championship : Has one League (A championship has a default League).

League: Has Many Competitors – Belongs to one Championship (Many leagues belong to one championship).

When I load the Championship entity, the associated League comes with the list of Competitors already loaded (even though I have lazy=true on my mapping file). I am pasting the relevant parts of the mapping files for these 3 entities:

***************************************************************************************
<class name="Championship" table="Championships">

<id name="id" type="long" column="id">
  <generator class="native" />
</id>
<many-to-one name="defaultLeague" lazy="false" cascade="all" class="League" not-null="true"  column="Default_League_FK"  unique="true" not-found="ignore"/>

</class>

****************************************************************************************
<class name="League" table="League">

<id name="id" type="long" column="id">
  <generator class="native" />
</id>

<many-to-one name="championship" lazy="false"
class="Championship" column="Championship_FK" />

<list name="competitorsList" table="Competitors_League" cascade="all" lazy="true">
    <key column="League_FK" not-null="true"/>
<index column="LeagueIndex" type="long"/>
<one-to-many class="Competitor" />
</list>

</class>
*****************************************************************************************
<class name="Competitor" table="Competitors_League" >

<key column="id"/>

<many-to-one name="league" lazy="false" class="League" not-null="true" insert="false" update="false" column="League_FK" />

</class>
******************************************************************************************

When I load a Championship instance, Championship --> league --> competitorsList comes already loaded with all list elements. This should not happen since I have lazy = true on my League mapping:

<list name=" competitorsList" table="Competitors_League" cascade="all" lazy="true">

I have tried many different approaches and I can get this to work, even though It seems that my mappings are set up correctly.

Can you guys please help me out here? Any help will be really appreciated cause I am kind of stuck here.

Let me know if you need any extra information. Thanks!

Comments notes

Note 1: The collection is accessed in the view layer (no open-session-in-view-filter stuff or anything like that here). I should be receiving "LazyInitializationException", that´s the expected behaviour, instead collection is eagerly loaded.

Note 2: I am adding class model in order to give some extra semantic context:

public class League{

   private Championship championship;
       private List<Competitor> competitorsList;

}

*********************************

public class Championship {

   private League defaultLeague;
}
**********************************

public class Competitor{

   private League league;
}

Note 3: Hibernate.isInitialized(league.competitorList) is returning TRUE. Fetch attributes removed but same behaviour.

Note 4: Logging does not show that the collection is fetched. I have set up DEBUG level (couldn´t make INFO level to throw results) and here it´s the console output.

19:14:35,953 DEBUG ErrorCounter:68 - throwQueryException() : no errors
19:14:35,959 DEBUG HqlSqlBaseWalker:111 - select << begin [level=1, statement=select]
19:14:35,966 DEBUG FromElement:108 - FromClause{level=1} :  com.sportsdt.model.championship (no alias) -> championship0_
19:14:35,972 DEBUG FromReferenceNode:51 - Resolved :  {synthetic-alias} -> {synthetic-alias}
19:14:35,979 DEBUG DotNode:569 - getDataType() : enJuego -> org.hibernate.type.BooleanType@1d50d84
19:14:35,985 DEBUG FromReferenceNode:51 - Resolved :  {synthetic-alias}.enJuego -> championship0_.en_juego
19:14:35,991 DEBUG FromReferenceNode:51 - Resolved :  {synthetic-alias} -> {synthetic-alias}
19:14:35,998 DEBUG DotNode:569 - getDataType() : competencia -> org.hibernate.type.ManyToOneType(com.sportsdt.model.Competencia)
19:14:36,004 DEBUG DotNode:526 - dereferenceShortcut() : property competencia in com.sportsdt.model.championship does not require a join.
19:14:36,011 DEBUG DotNode:555 - terminal propertyPath = [competencia]
19:14:36,017 DEBUG FromReferenceNode:51 - Resolved :  {synthetic-alias}.competencia -> championship0_.idCompetencia
19:14:36,023 DEBUG HqlSqlBaseWalker:117 - select : finishing up [level=1, statement=select]
19:14:36,030 DEBUG HqlSqlWalker:509 - processQuery() :  ( SELECT ( FromClause{level=1} championships championship0_ ) ( where ( and ( = ( championship0_.en_juego {synthetic-alias} enJuego ) ? ) ( = ( championship0_.idCompetencia {synthetic-alias} competencia ) ? ) ) ) )
19:14:36,036 DEBUG HqlSqlWalker:716 - Derived SELECT clause created.
19:14:36,042 DEBUG JoinProcessor:148 - Using FROM fragment [championships championship0_]
19:14:36,053 DEBUG HqlSqlBaseWalker:123 - select >> end [level=1, statement=select]
19:14:36,067 DEBUG AST:232 - --- SQL AST ---
-[SELECT] QueryNode: 'SELECT'  querySpaces (championships)
+-[SELECT_CLAUSE] SelectClause: '{derived select clause}'
|  +-[SELECT_EXPR] SelectExpressionImpl: 'championship0_.id as id29_' {FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=championships,tableAlias=championship0_,origin=null,colums={,className=com.sportsdt.model.championship}}}
|  \-[SQL_TOKEN] SqlFragment: 'championship0_.nombre as nombre29_, championship0_.cantidadFechas as cantidad3_29_, championship0_.fecha_inicio as fecha4_29_, championship0_.fecha_fin as fecha5_29_, championship0_.en_juego as en6_29_, championship0_.idCompetencia as idCompet7_29_, championship0_.disponible_penca as disponible8_29_, championship0_.disponible_entrenador as disponible9_29_, cha开发者_如何学JAVAmpionship0_.League_General_FK as League10_29_'
+-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=1, fromElements=1, fromElementByClassAlias=[], fromElementByTableAlias=[championship0_], fromElementsByPath=[], collectionJoinFromElementsByPath=[], impliedElements=[]}
|  \-[FROM_FRAGMENT] FromElement: 'championships championship0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=championships,tableAlias=championship0_,origin=null,colums={,className=com.sportsdt.model.championship}}
\-[WHERE] SqlNode: 'where'
   \-[AND] SqlNode: 'and'
      +-[EQ] BinaryLogicOperatorNode: '='
      |  +-[DOT] DotNode: 'championship0_.en_juego' {propertyName=enJuego,dereferenceType=4,propertyPath=enJuego,path={synthetic-alias}.enJuego,tableAlias=championship0_,className=com.sportsdt.model.championship,classAlias=null}
      |  |  +-[IDENT] IdentNode: '{synthetic-alias}' {originalText={synthetic-alias}}
      |  |  \-[IDENT] IdentNode: 'enJuego' {originalText=enJuego}
      |  \-[PARAM] ParameterNode: '?' {ordinal=0, expectedType=org.hibernate.type.BooleanType@1d50d84}
      \-[EQ] BinaryLogicOperatorNode: '='
         +-[DOT] DotNode: 'championship0_.idCompetencia' {propertyName=competencia,dereferenceType=ROOT_LEVEL,propertyPath=competencia,path={synthetic-alias}.competencia,tableAlias=championship0_,className=com.sportsdt.model.championship,classAlias=null}
         |  +-[IDENT] IdentNode: '{synthetic-alias}' {originalText={synthetic-alias}}
         |  \-[IDENT] IdentNode: 'competencia' {originalText=competencia}
         \-[PARAM] ParameterNode: '?' {ordinal=1, expectedType=org.hibernate.type.ManyToOneType(com.sportsdt.model.Competencia)}

19:14:36,074 DEBUG ErrorCounter:68 - throwQueryException() : no errors
19:14:36,080 DEBUG QueryTranslatorImpl:216 - HQL: from com.sportsdt.model.championship where enJuego=? and competencia=?
19:14:36,086 DEBUG QueryTranslatorImpl:217 - SQL: select championship0_.id as id29_, championship0_.nombre as nombre29_, championship0_.cantidadFechas as cantidad3_29_, championship0_.fecha_inicio as fecha4_29_, championship0_.fecha_fin as fecha5_29_, championship0_.en_juego as en6_29_, championship0_.idCompetencia as idCompet7_29_, championship0_.disponible_penca as disponible8_29_, championship0_.disponible_entrenador as disponible9_29_, championship0_.League_General_FK as League10_29_ from championships championship0_ where championship0_.en_juego=? and championship0_.idCompetencia=?
19:14:36,092 DEBUG ErrorCounter:68 - throwQueryException() : no errors
19:14:54,360 DEBUG JDBCTransaction:103 - commit
19:14:57,136 DEBUG JDBCTransaction:193 - re-enabling autocommit
19:14:57,141 DEBUG JDBCTransaction:116 - committed JDBC Connection

If I set log4j.logger.org.hibernate.SQL=debug it shows a great amount of select (as it´s expected) and these operations include select and joins against the table, but for what I saw this scrambled information is kind of useless.


Never used xml-based entity description, but the the link below might be useful for you.

http://java.sun.com/javaee/6/docs/api/javax/persistence/FetchType.html

Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified.

Another question is how you determine that competitors are eagerly loaded. For example any call to getCompetitorsList().size() will cause the list to be loaded. If this is not the case you should look for hibernate-specific configuration options which could guarantee lazy loading.


You are using one-to-one association. Don't. Your usage means the league and the champion have the same primary key.

The correct inverse of many-to-one is "set"

I cannot tell the arity from your description. But if a league has a single champion then in League you should have:

    <set name="allChampions" access="field"
        cascade="all-delete-orphan" lazy="true">
        <key column="league" not-null="true"/>
        <one-to-many class="Championship"/>
    </set>

likewise your "list" of competitors should probably be a set unless you have a reason for ordering the competitors.

btw whats with all the spaces at the beginning of class names?

Update:

  1. How do you know the list is being fetched eagerly? I would suggest turning on sql logging to make sure the debugging is not causing the problem.
  2. remove the fetch attributes. fetch affects loading and has side-effects on loading.

Use org.hibernate.Hibernate.isInitialized(league.competitorList) to find out if the list is truly initialized.

This log4j.xml snippet will help with the logging to determine exactly when the collection is fetched:

   <logger name="org.hibernate">
      <level value="INFO"/>
   </logger>
    <!-- log HQL query parser activity -->
   <logger name="org.hibernate.hql.ast.AST">
      <level value="INFO"/>
   </logger>
    <!-- log just the SQL -->
   <logger name="org.hibernate.SQL">
      <level value="INFO"/>
   </logger>
    <!-- log JDBC bind parameters     -->
   <logger name="org.hibernate.type">
      <level value="INFO"/>
   </logger>

    <!-- log schema export/update -->
   <logger name="org.hibernate.tool.hbm2ddl">
      <level value="INFO"/>
   </logger>

    <!-- log HQL parse trees -->
   <logger name="org.hibernate.hql">
      <level value="INFO"/>
   </logger>
    <!-- log cache activity -->
   <logger name="org.hibernate.cache">
      <level value="INFO"/>
   </logger>
    <!-- log transaction activity (TRACE for very detailed) -->
   <logger name="org.hibernate.transaction">
      <level value="INFO"/>
   </logger>
   <!-- log JDBC resource acquisition -->
   <logger name="org.hibernate.jdbc">
      <level value="INFO"/>
   </logger>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜