【问题标题】:Hibernate no session error on proxy object在代理对象上休眠没有会话错误
【发布时间】:2014-09-16 02:47:33
【问题描述】:

由于这个休眠延迟加载错误,我一直在努力编辑和更新嵌套对象。

在我的应用程序中:

  1. 我将图像集绑定到产品。
  2. 我已使用格式化程序将图像集转换为在选择框中使用,因此用户可以选择图像集。
  3. 如果表单成功,对象绑定并且关系正确保存,则效果很好。
  4. 但如果验证失败,每当 UI 层尝试访问嵌套对象值时,我都会收到可怕的延迟初始化/无会话错误!

所以我尝试编写一个方法来初始化相关对象作为解决方法:

@Transactional
public void initObject(Variant variant) {
    Hibernate.initialize(variant.getOption1());
    Hibernate.initialize(variant.getOption2());
    Hibernate.initialize(variant.getOption3());
    Hibernate.initialize(variant.getImageSet());
}

该方法的前 3 行有效(这些是单向的一对一),但第四行无效(这是多对一),它仍然表示没有代理。

我也尝试过将所有东西都设为 Eager fetch 类型。

这些都不起作用。

问题可能是我正在创建父对象,当出现验证错误时它不会保存到数据库中,但是无论获取类型如何,嵌套对象都是惰性代理对象(请参阅下面的格式化程序)。

我该如何解决这个问题?

这是格式化程序组件:

@Component
public class ImageSetFormatter implements Formatter<ProductImageSet> {

    private static Logger logger = LogManager.getLogger(VariantController.class.getName());

    @Autowired
    private ProductImageService imageService;

    @Override
    public ProductImageSet parse(String s, Locale locale) throws ParseException {
        logger.entry();

        Long imageSetId = Long.valueOf(s);
        logger.exit();
        return imageService.getImageSet(imageSetId);
    }

    @Override
    public String print(ProductImageSet productImageSet, Locale locale) {
        logger.entry();

        logger.exit();
        return Long.toString(productImageSet.getId());
    }
}

Stacktrace 当行 Hibernate.initialize(variant.getImageSet()) 被称为:

org.springframework.web.util.NestedServletException: 请求 处理失败;嵌套异常是 org.hibernate.LazyInitializationException:无法初始化代理 - 没有会话 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863) javax.servlet.http.HttpServlet.service(HttpServlet.java:644) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837) javax.servlet.http.HttpServlet.service(HttpServlet.java:725) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)

相关对象关系:

   @Entity
@Table(name="variants")
@EntityListeners({AuditingEntityListener.class})
public class Variant extends AbstractAuditable<Customer, Long> {

    @OneToOne
    private VariantOptionValue option1;

    @OneToOne
    private VariantOptionValue option2;

    @OneToOne
    private VariantOptionValue option3;

    ...

     @ManyToOne
    @JoinColumn(name="image_set_id")
    @LazyCollection(LazyCollectionOption.FALSE )
    private ProductImageSet imageSet;



}


@Entity
@Table(name="product_image_set")
@EntityListeners({AuditingEntityListener.class})
public class ProductImageSet extends AbstractAuditable<Customer, Long> {


    public ProductImageSet(String label)
    {
        this.label = label;
    }

    public ProductImageSet(){

    }

    @Basic
    @Column(length = 50, nullable = false)
    private String label;

    @OneToMany(mappedBy = "imageSet", fetch = FetchType.EAGER)
    private List<ProductImage> images;

    @OneToMany(mappedBy = "imageSet", fetch = FetchType.EAGER)
    private List<Variant> variants;

    private int sequence;

    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;

    ...
}

【问题讨论】:

  • 你能发布你得到的异常的实际堆栈跟踪吗?错误消息可能会提供有关错误是什么的线索。您能否也发布您正在使用的对象,或详细描述它们的关系(一个 X 有多个 Y,一个 Y 有一个 Z 等)
  • 您也可以发布对象关系的描述吗?你说的是父对象,但我需要知道什么是父对象,什么是子对象
  • 请注意,我已经尝试了一些 fetch = FetchType.EAGER 的变体,LazyCollection 只是我最新的修复尝试。

标签: hibernate spring-mvc jpa spring-orm


【解决方案1】:

您可能想尝试两件事。

1- 添加 OpenEntityManagerInViewFilter

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2- 将您的实体/表单/模型添加到会话中

@Controller
@SessionAttributes("yourEntityFormModel")
public class YourController {
    ...
}

--------- 更新

发生的情况是,在事务内部运行的带注释的方法中,Hibernate 将能够按需从该实体检索关系。

所以,下面的例子可以正常工作。

@Transactional
public void updateEmployeesFromDepartment(int depId) {

    Department dep = departmentRepository.findOne(dep.getId());
    for (Employee e : dep.getEmployees()) {
        // update whatever you want
    }

}

但我不希望这会起作用......

public void updateEmployeesFromDepartment(int depId) {

    Department dep = departmentRepository.findOne(dep.getId());
    for (Employee e : dep.getEmployees()) {
        // update whatever you want
    }

}

【讨论】:

  • 请参阅 this 了解为什么 1 号是个坏主意。
  • 另外,如果这是一个 RESTful 应用程序,那么 2 号会完全破坏任何 RESTful 实现,因为您通过将模型添加到会话中使其成为有状态的。
  • @JamesMassey 我明白这一点......虽然有争议......这是曾经拯救了一天但人们(!?!)不再喜欢它的那些合作伙伴之一。我确实更喜欢加载所有必需的信息以预先查看,但如果我可以在这里帮助朋友,他可以稍后决定是否喜欢。 :)
  • 这就是为什么我没有否决你的答案。我同意这曾经是一个解决方案,但在这种情况下可能没有帮助。我只是指出了可能的缺陷,以防 OP 不了解其含义
  • 您是如何发现它是 RESTful 实现的?我找不到任何指定的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 2013-04-30
  • 1970-01-01
相关资源
最近更新 更多