Коллекция загружается с нетерпением, даже если lazy = true? - PullRequest
1 голос
/ 01 сентября 2011

У меня проблема с отложенной загрузкой Hibernate. Я разместил это на форуме Hibernate, но ответа не получил, поэтому подумал, что, возможно, вы, ребята, здесь, на stackoverflow, можете мне помочь. Ссылка на пост: https://forum.hibernate.org/viewtopic.php?f=1&t=1012419 Я копирую содержание ниже, спасибо заранее:

Проблема в том, что я пытаюсь лениво загрузить коллекцию, но она постоянно загружается, оказывая огромное влияние на производительность моего приложения. Вот сценарий, я опишу модель для 3 классов:

Чемпионат : имеет одну Лигу (Чемпионат имеет Лигу по умолчанию).

Лига : имеет множество участников - принадлежит одному чемпионату (многие лиги принадлежат одному чемпионату).

Когда я загружаю сущность Чемпионата, связанная Лига приходит со списком уже загруженных Конкурентов (даже если у меня в файле сопоставления lazy = true). Я вставляю соответствующие части файлов сопоставления для этих 3 объектов:

***************************************************************************************
<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>
******************************************************************************************

Когда я загружаю экземпляр Championship, Championship -> league -> CompetitorsList уже загружен всеми элементами списка. Этого не должно случиться, так как у меня есть lazy = true в моем отображении Лиги:

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

Я пробовал много разных подходов, и я могу заставить это работать, хотя кажется, что мои сопоставления настроены правильно.

Не могли бы вы, ребята, помочь мне здесь? Буду очень признателен за любую помощь, потому что я застрял здесь.

Дайте мне знать, если вам нужна дополнительная информация. Спасибо!

Комментарии примечания

Примечание 1: Доступ к коллекции осуществляется в слое представления (здесь нет содержимого для открытия сеанса в фильтре или чего-либо подобного). Я должен получить «LazyInitializationException», это ожидаемое поведение, вместо этого коллекция загружается с нетерпением.

Примечание 2: Я добавляю модель класса, чтобы придать дополнительный семантический контекст:

public class League{

   private Championship championship;
       private List<Competitor> competitorsList;

}

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

public class Championship {

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

public class Competitor{

   private League league;
}

Примечание 3: Hibernate.isInitialized (league.competitorList) возвращает TRUE. Извлеченные атрибуты удалены, но то же самое поведение.

Примечание 4: Ведение журнала не показывает, что коллекция извлекается. Я установил уровень DEBUG (не мог сделать уровень INFO для выдачи результатов), и вот он - вывод консоли.

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_, championship0_.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

Если я установлю log4j.logger.org.hibernate.SQL = debug, он показывает большое количество выбора (как и ожидалось), и эти операции включают в себя выбор и объединения с таблицей, но, как я увидел, это зашифрованная информация вид бесполезен.

Ответы [ 2 ]

0 голосов
/ 02 сентября 2011

Вы используете однозначную связь.Не.Ваше использование означает, что лига и чемпион имеют один и тот же первичный ключ.

Правильное значение обратного ко многим к одному "установлено"

Я не могу сказать, насколько это верно из вашего описания.Но если в лиге есть один чемпион, то в Лиге вы должны иметь:

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

аналогично, ваш "список" участников, вероятно, должен быть сетом, если у вас нет причины для заказа участников.

Кстати, что со всеми пробелами в начале имен классов?

Обновление:

  1. Откуда вы знаете, что список загружается с нетерпением?Я бы предложил включить ведение журнала sql, чтобы убедиться, что отладка не вызывает проблемы.
  2. удалите атрибуты извлечения.fetch влияет на загрузку и имеет побочные эффекты при загрузке.

Используйте org.hibernate.Hibernate.isInitialized (league.competitorList), чтобы узнать, действительно ли список инициализирован.

ЭтоФрагмент log4j.xml поможет при ведении журнала точно определить, когда будет извлечена коллекция:

   <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 голосов
/ 02 сентября 2011

Никогда не использовал описание сущностей на основе xml, но ссылка ниже может быть полезной для вас.

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

Определяет стратегии для извлечения данных из базы данных. EAGER Стратегия является требованием времени выполнения провайдера, что данные должны быть с нетерпением извлечены. Ленивая стратегия - это подсказка к Постоянная работа провайдера, что данные должны извлекаться лениво, когда это первый доступ. Реализации разрешено охотно получать данные, для которых указана стратегия LAZY .

Другой вопрос, как вы определяете, что конкуренты загружены. Например, любой вызов getCompetitorsList().size() приведет к загрузке списка. Если это не так, вам следует искать специфичные для hibernate параметры конфигурации, которые могут гарантировать отложенную загрузку.

...