服务层中的惰性关系初始化

时间:2013-03-22 19:25:16

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

我有一个延迟加载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>

2 个答案:

答案 0 :(得分:1)

最快的修复方法可能是让收藏热切。即:

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

否则出现此错误的原因有很多:

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

答案 1 :(得分:1)

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

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