Почему не работает JPA FetchType.LAZY?

Поставщик JPA eclipselink 2.3 AS glassfish 3.1.1 B12 Двоичный протокол для удаленного вызова Hessian

На стороне сервера ejb + jpa На стороне клиента Plain Swing.

Сопоставления JPA

@Entity
@Table(name = "FATHER", catalog = "CAT", schema = "dbo")
public class Father implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(generator = "FATHERUID", strategy = GenerationType.TABLE)
    @TableGenerator(name = "FATHERUID", table = "FAMILY_UID", catalog = "LSDB", schema = "dbo", pkColumnName = "PRIM", pkColumnValue = "father_uid", valueColumnName = "UID", allocationSize = 1, initialValue = 0)
    private Long id;

    @OneToOne(mappedBy = "father", fetch = FetchType.LAZY)
    private Mother mother;

    @OneToMany(mappedBy = "father", fetch = FetchType.LAZY)
    private List<Friend> friendList;

}


@Entity
@Table(name = "FRIEND", catalog = "CAT", schema = "dbo")
@NamedQueries({
    @NamedQuery(name = "Friend.findAll", query = "SELECT f FROM Friend f")})
public class Friend implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(generator = "FRIENDUID", strategy = GenerationType.TABLE)
    @TableGenerator(name = "FRIENDUID", table = "FAMILY_UID", catalog = "LSDB", schema = "dbo", pkColumnName = "PRIM", pkColumnValue = "friend_uid", valueColumnName = "UID", allocationSize = 1, initialValue = 0)
    private Long id;

    @JoinColumn(name = "FATHERID", referencedColumnName = "ID")
    @ManyToOne(optional = false,fetch= FetchType.LAZY)
    private Father father;

}

Метод EJB

   public Father findFather(long id) {

        Father fath = em.find(Father.class, id);

        PersistenceUnitUtil util = em.getEntityManagerFactory().getPersistenceUnitUtil();

        System.out.println("mother isloaded="+util.isLoaded(fath,"mother"));
        System.out.println("friendList isloaded="+util.isLoaded(fath,"friendList"));

        return fath;
    }

Звонок на стороне клиента по гессенской земле

   public void findFather() {

        try {

        IManager manager = ProxyHelper.getStub();
       //find by father id
        Father father = manager.findFather(3500L);

        System.out.println("Father=" + father);
        System.out.println("father's friends=" + father.getFriendList());
        System.out.println("mother=" + father.getMother());

  } catch (MalformedURLException ex) {

  }

 }

все работает нормально, но при просмотре журнала сервера и сторон, связанных с отцовской сущностью, я обнаружил, что аннотированные поля LazyLoaded заполняются из базы данных.

Журнал сервера

FINEST: Begin deploying Persistence Unit test; session file:/C:/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test; state Predeployed; factoryCount 1
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
FINEST: property=eclipselink.target-server; value=SunAS9; translated value=org.eclipse.persistence.platform.server.sunas.SunAS9ServerPlatform
FINEST: property=eclipselink.logging.level; value=FINEST; translated value=FINEST
FINEST: property=eclipselink.logging.parameters; value=true
FINEST: property=eclipselink.logging.level; value=FINEST; translated value=FINEST
FINEST: property=eclipselink.logging.parameters; value=true
FINEST: property=eclipselink.cache.shared.default; value=false; translated value=false
INFO: EclipseLink, version: Eclipse Persistence Services - 2.3.2.v20111125-r10461
FINEST: Database platform: org.eclipse.persistence.platform.database.oracle.Oracle11Platform, regular expression: (?i)oracle.*11
FINEST: Database platform: org.eclipse.persistence.platform.database.oracle.Oracle10Platform, regular expression: (?i)oracle.*10
FINEST: Database platform: org.eclipse.persistence.platform.database.oracle.Oracle9Platform, regular expression: (?i)oracle.*9
FINEST: Database platform: org.eclipse.persistence.platform.database.oracle.OraclePlatform, regular expression: (?i)oracle.*
FINEST: Database platform: org.eclipse.persistence.platform.database.SQLAnywherePlatform, regular expression: SQL\ Anywhere.*
FINEST: Database platform: org.eclipse.persistence.platform.database.SybasePlatform, regular expression: (?i)(sybase.*)|(adaptive\ server\ enterprise.*)|(SQL\ Server.*)
FINEST: Database platform: org.eclipse.persistence.platform.database.SQLServerPlatform, regular expression: (?i)microsoft.*
FINE: Detected database platform: org.eclipse.persistence.platform.database.SQLServerPlatform
CONFIG: connecting(DatabaseLogin(
    platform=>DatabasePlatform
    user name=> ""
    connector=>JNDIConnector datasource name=>null
))
CONFIG: Connected: jdbc:jtds:sqlserver:
    User: user
    Database: Microsoft SQL Server  Version: 10.50.1600
    Driver: jTDS Type 4 JDBC Driver for MS SQL Server and Sybase  Version: 1.2.5
FINEST: Connection acquired from connection pool [read].
FINEST: Connection released to connection pool [read].
CONFIG: connecting(DatabaseLogin(
    platform=>SQLServerPlatform
    user name=> ""
    connector=>JNDIConnector datasource name=>null
))
CONFIG: Connected: jdbc:jtds:sqlserver:
    User: user
    Database: Microsoft SQL Server  Version: 10.50.1600
    Driver: jTDS Type 4 JDBC Driver for MS SQL Server and Sybase  Version: 1.2.5
FINEST: sequencing connected, state is Preallocation_Transaction_NoAccessor_State
FINEST: sequence child_uid: preallocation size 1
FINEST: sequence friend_uid: preallocation size 1
FINEST: sequence father_uid: preallocation size 1
FINEST: sequence mother_uid: preallocation size 1
INFO: file:/C:/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test login successful
WARNING: Multiple [2] JMX MBeanServer instances exist, we will use the server at index [0] : [com.sun.enterprise.v3.admin.DynamicInterceptor@266bad10].
FINER: JMX MBeanServer instance found: [com.sun.enterprise.v3.admin.DynamicInterceptor@266bad10], # of beans: [21], domain: [DefaultDomain] at index: [0].
WARNING: JMX MBeanServer in use: [com.sun.enterprise.v3.admin.DynamicInterceptor@266bad10] from index [0] 
FINER: JMX MBeanServer instance found: [com.sun.jmx.mbeanserver.JmxMBeanServer@6f7adf19], # of beans: [24], domain: [DefaultDomain] at index: [1].
WARNING: JMX MBeanServer in use: [com.sun.jmx.mbeanserver.JmxMBeanServer@6f7adf19] from index [1] 
FINEST: Registered MBean: org.eclipse.persistence.services.mbean.MBeanDevelopmentServices[TopLink:Name=Development-file_/C_/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test,Type=Configuration] on server com.sun.jmx.mbeanserver.JmxMBeanServer@6f7adf19
FINEST: Registered MBean: org.eclipse.persistence.services.glassfish.MBeanGlassfishRuntimeServices[TopLink:Name=Session(file_/C_/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test)] on server com.sun.jmx.mbeanserver.JmxMBeanServer@6f7adf19
FINEST: EclipseLink JMX Runtime Services is referencing the [Platform ConversionManager] ClassLoader at: [WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)]
FINEST: The applicationName for the MBean attached to session [file:/C:/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test] is [unknown]
FINEST: The moduleName for the MBean attached to session [file:/C:/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test] is [unknown]
FINER: Canonical Metamodel class [org.dima.model.Child_] not found during initialization.
FINER: Canonical Metamodel class [org.dima.model.Friend_] not found during initialization.
FINER: Canonical Metamodel class [org.dima.model.Father_] not found during initialization.
FINER: Canonical Metamodel class [org.dima.model.Mother_] not found during initialization.
FINEST: End deploying Persistence Unit test; session file:/C:/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test; state Deployed; factoryCount 1
FINER: client acquired: 50658177
FINER: TX binding to tx mgr, status=STATUS_ACTIVE
FINER: acquire unit of work: 1008456627
FINEST: Execute query ReadObjectQuery(name="readObject" referenceClass=Father sql="SELECT ID, NAME, SURNAME FROM LSDB.dbo.FATHER WHERE (ID = ?)")
FINEST: Connection acquired from connection pool [read].
FINEST: reconnecting to external connection pool
FINE: SELECT ID, NAME, SURNAME FROM LSDB.dbo.FATHER WHERE (ID = ?)
    bind => [3500]
FINEST: Connection released to connection pool [read].
INFO: mother isloaded=false
INFO: friendList isloaded=false
FINER: TX beforeCompletion callback, status=STATUS_ACTIVE
FINER: begin unit of work commit
FINER: TX afterCompletion callback, status=COMMITTED
FINER: end unit of work commit
FINER: release unit of work
FINER: client released
FINEST: Execute query ReadAllQuery(name="file:/C:/netbeans/projects/JPATestServer/build/web/WEB-INF/classes/_test" referenceClass=Friend )
FINEST: Connection acquired from connection pool [read].
FINEST: reconnecting to external connection pool
**FINE: SELECT ID, NAME, SURNAME, FATHERID FROM LSDB.dbo.FRIEND WHERE (FATHERID = ?)
    bind => [3500]**
FINEST: Connection released to connection pool [read].
FINEST: Register the existing object org.dima.model.Friend[ id=17496 ]
FINEST: Register the existing object org.dima.model.Friend[ id=17497 ]
FINEST: Register the existing object org.dima.model.Friend[ id=17498 ]
FINEST: Register the existing object org.dima.model.Friend[ id=17499 ]
FINEST: Register the existing object org.dima.model.Friend[ id=17500 ]

Почему провайдер JPA выполняет этот SELECT ID, NAME, SURNAME, FATHERID FROM LSDB.dbo.FRIEND WHERE (FATHERID =?) Bind => [3500]

Любая идея?


person dimitri    schedule 14.12.2011    source источник


Ответы (3)


Ленивая загрузка выполняется только для отношения xToMany в среде Java SE по умолчанию (поскольку EclipseLink может использовать IndirectList там, где используются коллекции). Если вы хотите отложить загрузку отношений xToOne, вы должны использовать переплетение классов.

person Klaus Groenbaek    schedule 24.10.2012
comment
Вы король лаборатории. Я люблю вас. - person Alex; 25.09.2013

Тип ленивой выборки работает. Ленивые отношения позволяют отложить выборку ссылочных сущностей до тех пор, пока к ним не будет осуществлен первый доступ, что, похоже, происходит, когда вы вызываете Father.getFriendList (). Если бы это не сработало, этот вызов бы ничего не сделал, и связь была бы установлена ​​немедленно, когда был прочитан отец.

EclipseLink позволяет получить доступ к ленивым отношениям, пока соединение все еще доступно, как описано здесь: http://dev.eclipse.org/mhonarc/lists/eclipselink-users/msg05258.html Если вы сериализуете объект, вы получите исключение, поскольку контекст для чтения в связи будет недоступен.

Если вы хотите, чтобы вместо этого генерировалось исключение при доступе к ленивым отношениям на отсоединенном, но не сериализованном объекте, отправьте запрос на расширение в EclipseLink.

person Chris    schedule 14.12.2011
comment
Разве не (неявный) вызов метода toString () списка вызывает отложенную загрузку? - person JB Nizet; 14.12.2011
comment
Кроме того, я считаю такое поведение (ленивой загрузки после фиксации транзакции) сомнительным: если транзакция имеет уровень изоляции READ_COMMITTED (или более строгий), отложенная загрузка списка после завершения транзакции позволяет видеть дочерние элементы, которых не существовало, когда транзакция выполнена, и не отображаются дочерние элементы, которые существовали на момент выполнения транзакции, но с тех пор были удалены. Вы теряете I и C в КИСЛОТЕ. - person JB Nizet; 14.12.2011
comment
Ленивая загрузка работает нормально, но при первом доступе к отцовскому серверу сущностей выполняет sql select на «Друзьях отца». как остановить выполнение sql для дочернего объекта SELECT ID, NAME, SURNAME, FATHERID FROM LSDB.dbo.FRIEND WHERE (FATHERID =?) bind = ›[3500] - person dimitri; 14.12.2011
comment
SQL должен выдаваться только при доступе к коллекции, поэтому, если вы не хотите, чтобы она была введена, узнайте, как к ней обращаются. Распространенные причины - методы toString, обращающиеся к ленивым отношениям. Что касается read_commited и изоляции, я не вижу проблемы с возвратом текущего состояния коллекции после того, как транзакция была зафиксирована, поскольку, если бы состояние до транзакции требовалось, оно было бы инициировано внутри транзакции. В большинстве случаев, которые я видел, нужны данные сейчас, а не исключение, которое заставит их перечитать родительские / дочерние экземпляры. - person Chris; 15.12.2011
comment
Я обнаружил, что если вызвать ejb throw hessian protocol, тогда поля, отмеченные как нетерпеливые, заполняются из базы данных, где аннотация - @OneToMany. Из тестового сервлета jpa выполняет запрос выбора только для запрошенной сущности. - person dimitri; 16.12.2011

Стратегия EAGER - это требование к среде выполнения поставщика сохраняемости, что значение должно быть быстро извлечено. Стратегия LAZY - это подсказка для среды выполнения поставщика сохраняемости.

Нашел этот ответ здесь. JPA fetchType.Lazy не работает

Еще одна вещь: JPA использует для этого ткачество. wiki-eclipse

person CodeShadow    schedule 21.09.2015