【问题标题】:Lazy relationship initialization in service layer服务层延迟关系初始化
【发布时间】:2013-03-22 19:25:15
【问题描述】:

我有一个具有 OneToMany 关系延迟加载的 JPA 实体。
我使用 Sping Data JPA 来检索实体,在我的服务方法中,我需要检索初始化的列表,因为我需要在 JSP 中打印它。 我所做的是:

@Override
@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
public User retrieveUser(String username) {
    final User user = userRepository.findByUsername(username);
    user.getFriends().size(); //This line throws a LazyInitializationException
    return user;
}

但是这个解决方案不起作用也不优雅,我该如何实现呢?

例外是:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: it.nikeconsulting.chirp.domain.User.follows, no session or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:489)
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:447)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:139)
at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:242)
at it.nikeconsulting.chirp.domain.service.ChirpUserServiceImpl.retrieveUser(ChirpUserServiceImpl.java:26)

我的 context.xml 是:

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="it.nikeconsulting.chirp.domain" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="nestedTransactionAllowed" value="true" />
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="jpaVendorAdapter">
    <property name="showSql" value="true" />
    <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/>
 </bean>

【问题讨论】:

    标签: hibernate jpa lazy-loading spring-data-jpa


    【解决方案1】:

    最快的解决方法可能是让收藏变得急切。即:

    class User {
    ....
      @OneToMany( ..., fetch=FetchType.EAGER)
      private Collection<Friend> friends;
    ...
    }
    

    否则这个错误的原因有很多:

    • 该服务不是 Spring 托管的 bean - 因此方法上的 @Transactional 什么都不做。
    • 如果是Spring托管的bean,事务管理器是否配置正确?
    • 如果是,则该对象可能已分离。 (意味着导航惰性关联不起作用。)当 find 方法不是事务性的时会发生这种情况。您需要先附加它。这是您可以通过...保存(即合并)来完成的事情。不知道 Spring Data 有没有 attach 方法。

    【讨论】:

    • 我正在做的只是一个练习,所以我想以适当的方式解决它。我对JPA不太了解,那可能是什么问题?我将我的服务声明为 @Service 并由 Spring 注入我还声明了 transactionManager 但不确定是否正确...我应该设置什么才能使其正常工作?一些文档参考资料?
    • 那我认为你的对象没有附加。使用 save 方法获取对象的附加版本。在@transactional 方法中。应该这样做。
    【解决方案2】:

    问题是我在 servletroot 应用程序中都有一个 context:component-scan,并且都初始化了我的 Service 但在一个servlet 中的事务未初始化,因此当服务注入控制器时,它使用没有事务管理的控制器。

    解决方案是更改 servletcontext:component-scan 中的包,让它只扫描控制器。

    【讨论】:

    • 你为我节省了很多时间。我有同样的问题。我正在扫描我的 MVCConfig 文件中的服务。
    猜你喜欢
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 2020-10-08
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多