【问题标题】:LazyInitializationException by using Spring MVC with AJAX / JSON & MappingJacksonLazyInitializationException 使用带有 AJAX / JSON 和 MappingJackson 的 Spring MVC
【发布时间】:2011-05-21 15:22:16
【问题描述】:

我正在使用 Spring MVC、AJAX/JSON 和 Hibernate 从 MySQL 数据库中获取所有人。 我编写了 JUnit 集成测试来验证我的服务,一切正常。

现在我这样称呼它:

@RequestMapping(value="/allpersons", method=RequestMethod.GET)
public @ResponseBody Set<Person> getAllPersons() {
    Set<Person> persons= new PersonServiceImpl().getAllPersons();
    return persons;
}

我调试了它。与

的行
return persons;

一切都很好。我有一个包含所有人的 HashSet。 调试更多步骤,我来到了这一行:

this.objectMapper.writeValue(jsonGenerator, o);

在

org.springframework.http.converter.json.MappingJacksonHttpMessageConverter

然后我看不到源代码,但是我的调试器告诉我:

StdSerializerProvider._serializeValue(JsonGenerator, Object) line 297

在这一行之后,我得到了错误:

错误:org.hibernate.LazyInitializationException - 无法延迟初始化角色集合:com.mydomain.project.dom.Person.projects,没有会话或会话已关闭
org.hibernate.LazyInitializationException:未能延迟初始化角色集合:com.mydomain.project.dom.Person.projects,没有会话或会话已关闭
    在 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    在 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    在 org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)
    在 org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)
    在 org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186)
    在 org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:339)
    在 org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:314)
    在 org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:112)
    在 org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:268)
    在 org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:160)
    在 org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:131)
    在 org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:363)
    在 org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:314)
    在 org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:112)
    在 org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:297)
    在 org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:224)
    在 org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1030)
    在 org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:153)
    在 org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:181)
    在 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.writeWithMessageConverters(AnnotationMethodHandlerAdapter.java:975)
    在 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.handleResponseBody(AnnotationMethodHandlerAdapter.java:933)
    在 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.getModelAndView(AnnotationMethodHandlerAdapter.java:882)
    在 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:428)
    在 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
    在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
    在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    在 javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    在 javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    在 org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
    在 org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
    在 org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
    在 org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
    在 org.tukey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:195)
    在 org.tukey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:159)
    在 org.tukey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:141)
    在 org.tukey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:90)
    在 org.tukey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:417)
    在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    在 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    在 org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
    在 org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    在 org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    在 java.lang.Thread.run(Thread.java:619)

看来,这与序列化/JacksonMapping 有关。它想获取一个人的相关项目,这些项目不需要,通常是懒加载的。

这里有什么问题?

在此先感谢您并致以最诚挚的问候。

【问题讨论】:

  • 这个问题有大约一百万个结果。在 SO 和 google 上。
  • 因为它必须序列化整个对象层次结构
  • 如何避免这种情况?我不希望这会尝试获取更多数据? fetch 类型应该是惰性的,而不是急切的。
  • 默认情况下这个不起作用的问题是杰克逊需要对第三方库(hibernate)有很好的了解才能进行特殊处理——基本过程是遵循属性,序列化.

标签: java hibernate spring-mvc jackson


【解决方案1】:

您遇到的情况与此类似: Lazy Loading error

简而言之,您是在 Hibernate Session 之外访问延迟加载的集合。

可能的解决方案:

  • 急切地获取它
  • 确保您的 Hibernate 会话在您访问该集合时仍处于打开状态。您可以使用 OpenSessionInView 过滤器。这本身可能还不够,因为 Hibernate 可能会结束您关闭事务的会话。因此,您将需要扩展您的事务范围或找到一种方法来防止 Hibernate 在事务结束时关闭会话。
  • 确保访问事务中的延迟加载集合,以确保 Hibernate 加载它。

请查看上面指定的帖子以获取更多详细信息。

更新 1 据我了解,这是由于 Jackson 映射器接收到未完全加载的模型(某些集合是延迟加载的)引起的。你是说你不需要杰克逊映射这些集合中的对象。我看到的替代方案是:

  • 给 Jackson 一个正确的模型,基于您的 Person 对象创建的简单 POJO,仅包含您想与 Jackson 映射的信息。因此,与其给 Jackson 一个 Persons 列表,不如给它一个 PersonDetails 列表(或者你想怎么称呼它们)
  • 将 Jackson 配置为忽略该集合 - 不确定这是否可行

希望这会有所帮助。

【讨论】:

  • 当我获取所有需要的数据后,我将所有内容封装在我的 Dao 类中。序列化是在最后一步完成的,我无法控制。
  • 您可以在事务中显式访问项目集合,以强制 Hibernate 加载它。否则,您的事务将结束,Hibernate 会话将关闭,当映射器尝试访问该集合时,它将失败,因为会话已经关闭,因此无法获取该集合..
  • 我想懒加载。加载人员时我不需要这些项目。那么,解决这个问题的最佳方法是什么?我应该停止使用 ORM Hibernate 获取域对象而只获取我真正需要的数据(在这种情况下只有名字和姓氏)还是专业的 Java 程序员如何处理这个?
  • 您返回的模型似乎不适合您想要的渲染操作。我会说不是返回不完整的 Person 对象,而是创建一个仅用于渲染的 POJO。这个 POJO 可以由您显式创建,因此 JSON 映射器不会尝试访问它不应该访问的东西。另一种方法是将 Jackson 配置为不访问该特定集合(没有使用 Jackson,所以我不知道这是否可能)
  • 所以我应该在与数据库映射的 Person.java 之外创建一个 PersonPojo.class,我将 Person.java 的所有值放入 PersonPojo.java 中?或者我该如何处理?
【解决方案2】:

虽然这并不能立即帮助您轻松解决问题,但最好知道有一个新的与 Jackson 相关的项目 jackson-module-hibernate(在 GitHub 上)旨在解决此问题以及其他常见问题用例.

但在短期内,您可能会发现这篇文章很有用:http://kyrill007.livejournal.com/2577.html

【讨论】:

  • 前几天我也看到了。我将使用 POJO,然后,如果它更稳定,我将切换到这样的解决方案。但是非常感谢您提供的有用评论!
  • 没问题。我希望它会起作用,Jackson + Hibernate 是一个潜在的好组合,很难让它正常工作。
【解决方案3】:

如果你不想在你的 JSON 对象中映射在休眠关系中链接的字段,你可以在你的模型类中添加注释“@JsonIgnore”:

@JsonIgnore
@OneToMany(mappedBy = "person")
private List<ProjectEntity> projects = new ArrayList<ProjectEntity>();

【讨论】:

    【解决方案4】:
    猜你喜欢
    • 1970-01-01
    • 2014-07-11
    • 1970-01-01
    • 2018-06-10
    • 2014-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    相关资源
    最近更新 更多