LazyInitializationException 和 @Transactional 不起作用

Posted

技术标签:

【中文标题】LazyInitializationException 和 @Transactional 不起作用【英文标题】:LazyInitializationException and @Transactional not working 【发布时间】:2017-09-15 12:17:17 【问题描述】:

我正在使用 Spring 3.2.9,它具有多层架构设计,分为 3 个模块 Web、服务、存储库。在存储库中,我定义了一个由其他实体特定 DAO 类继承的通用 DAO 类。

问题是当我尝试从服务层延迟获取我的实体集合时,我总是得到 LazyInitializationException。我尝试将@Transactional 放在我的服务类上,但它似乎不起作用。如果我立即在 DAO 类方法中初始化所有惰性集合(并且仅当我使用 @Transactional 注释 DAO 类),我只能避免异常,但我只想在业务逻辑中需要它们时才获取这些集合,而不是全部提前。

奇怪的是@Transactional 只在DAO 层有效,在Service 层无效,应该使用它。我找到了几种解决这个问题的方法,但我有兴趣真正低估和解决这个问题,而不仅仅是让代码工作。

存储库模块:

@Repository
public abstract class GenericDao<T> 

    protected Class<T> entityClass;

    @PersistenceContext
    protected EntityManager entityManager;

    .........

    public T findById(long id) 
        T entity = entityManager.find(entityClass, id);
        if (entity == null) 
            throw new EntityNotFoundException(entityClass.getSimpleName(), id);
        

        return entity;
    

我在服务模块中的服务类:

@Service
public class UserServiceImpl implements UserService 

    private UserDao userDao;

    @SuppressWarnings("SpringJavaAutowiringInspection")
    @Autowired
    public UserServiceImpl(UserDao userDao) 
        this.userDao = userDao;
    

    @Transactional(readOnly = true)
    @Override
    public UserDto getUserById(long id) 
        User user = userDao.findById(id);

        return new UserDto(user);
    

DTO 构造函数尝试访问 user.getTeams(),然后发生异常。取而代之的是,应该通过对 DB 的附加查询来获取集合。

配置:

存储库配置: ......其他一些配置,如数据源......

<!--EntityManagerFactory-->
<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="jpaPropertyMap">
        <map>
            <entry key="hibernate.dialect" value="$hibernate_dialect"/>
            <entry key="hibernate.hbm2ddl.auto" value="$hibernate_Hbm2ddlAuto"/>
            <entry key="hibernate.show_sql" value="$hibernate_showSql"/>
            <entry key="hibernate.format_sql" value="$hibernate_formatSql"/>
        </map>
    </property>
</bean>

persistence.xml:

<persistence-unit name="persistenceUnit">
    ...other classes..
    <class>com.example.entity.User</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
    </properties>
</persistence-unit>

服务配置:

<import resource="classpath*:META-INF/repositoryApplicationContext.xml"/>

<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

【问题讨论】:

检查配置。请参阅:***.com/questions/10538345/… 试试这个 @AlanHay 谢谢我在那里找到了答案。 @user1601401 我的配置中已经有它,但在正确的 xml 中没有。 【参考方案1】:

看起来用户和他或她的团队之间的@OneToMany 关联是延迟加载的。当您将它们分配给 Dto 时,它仍然是代理而不是真正的集合。在那里放置一个断点并在调试模式下查看它。记住任何要求(让一个团队或它的规模让它活着)。一种方法是在查询中获取它们,但是

entityManager.find(entityClass, id)

没有选项。你可以使用

Hibernate.initialize(user.getTeams())

【讨论】:

是的,我知道,这与调用 getTeams().size() 相同。还是谢谢【参考方案2】:

经过几天的头痛找到了答案。 我不得不搬家:

<import resource="classpath*:META-INF/repositoryApplicationContext.xml"/>
<tx:annotation-driven/>

从 repositoryConfiguration.xml 到 dispatcher-servlet.xml,因为那是 Spring 的父上下文。

感谢您的帮助。

【讨论】:

以上是关于LazyInitializationException 和 @Transactional 不起作用的主要内容,如果未能解决你的问题,请参考以下文章