【问题标题】:LazyInitializationException when converting Entities within Transaction转换事务中的实体时出现 LazyInitializationException
【发布时间】:2015-07-26 16:52:45
【问题描述】:

在将域对象从数据库转换为客户端的资源对象期间,我遇到了延迟加载字段的问题。

  • Customer: 实体从数据库中加载,带有惰性字段
  • FullCustomer:将发送给客户端的实体。

服务层:

@Transactional(readOnly=true)
public Customer getById(Long id){
    return customerRepository.getById(id);
}

控制器:

@Autowired
private ResourceAssembler<Customer, FullCustomer> converter;

@RequestMapping(...)
public final FullCustomer getCustomerById(long cid) {
    Customer customer = customerService.getById(cid);
    return converter.convert(customer);
}

转换器 (ResourceAssembler&lt;Customer, FullCustomer&gt;)

@Override
@Transactional(readOnly = true)
public FullCustomer convert(Customer input) {
    System.err.println("Is open: " + TransactionSynchronizationManager.isActualTransactionActive());  //prints true

    FullCustomer fullCustomer = new FullCustomer();
    BeanUtils.copyProperties(input, fullCustomer);  //Fails
    return fullCustomer;
}

所以我的控制器使用转换器将数据库实体转换为客户端的实体。转换触发加载其他延迟加载的实体。

我的问题:虽然转换函数打开了一个新事务(Is open 打印true),但我得到了这个异常:

org.springframework.http.converter.HttpMessageNotWritableException: 
    Could not write content: failed to lazily initialize a collection of role: [..], could not initialize proxy - no Session (..); 
    nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: ...

在使用 BeanUtils 之前访问延迟加载的字段时,我得到以下信息:

org.hibernate.LazyInitializationException: 
    failed to lazily initialize a collection of role: [..], could not initialize proxy - no Session

为什么会这样?

【问题讨论】:

    标签: java spring hibernate jackson spring-data


    【解决方案1】:

    您从一个事务加载客户,而该事务不会初始化延迟加载的字段。然后提交该事务并关闭关联的 Hibernate 会话,从而使客户实体分离。然后你开始另一个事务,尝试初始化分离客户的惰性字段。

    那行不通:您需要从加载客户的同一事务中加载惰性字段。所以

    • 使您的控制器方法具有事务性,或者
    • 初始化 getById() 中的惰性字段,或者
    • 在存储库中使用连接提取,以确保查询加载客户和所需的关联,或者
    • 让 getById() 返回一个 FullCustomer
    • 使用 OpenEntityManagerInView 拦截器/过滤器(并使您的转换器非事务性)

    【讨论】:

    • 有没有办法重新附加现有实体?在我的服务层中加载字段不是一个选项,将@Transactional 添加到我的控制器无法创建事务。
    • 没有。您必须通过其 ID 重新加载实体,使您的服务层完全无用。第五个选项是使用 OpenEntityManagerInView 拦截器/过滤器。
    猜你喜欢
    • 1970-01-01
    • 2015-07-31
    • 2012-05-28
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多