Spring JPA Lazy Loading - 无法初始化代理

时间:2015-08-09 20:47:01

标签: java jpa lazy-loading spring-data-jpa lazy-initialization

下面是一些背景代码:

InitiativeProfileQuestion.java:

@Entity
@Table
public class InitiativeProfileQuestion implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String question;

    @Column
    private String description;

    @Column
    private int sortOrder;

    @OneToMany(mappedBy = "initiativeProfileQuestion", fetch = FetchType.LAZY)
    private List<InitiativeProfileAnswer> answers;

    public List<InitiativeProfileAnswer> getAnswers() {
        return answers;
    }

    public void setAnswers(List<InitiativeProfileAnswer> answers) {
        this.answers = answers;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getQuestion() {
        return question;
    }

    public void setQuestion(String question) {
        this.question = question;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(int sortOrder) {
        this.sortOrder = sortOrder;
    }

}

InitiativeProfileAnswer.java:

@Entity
@Table
public class InitiativeProfileAnswer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column
    private String answer;

    @Column
    private int sortOrder;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "initiativeProfileQuestionId")
    @JsonIgnore
    private InitiativeProfileQuestion initiativeProfileQuestion;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getAnswer() {
        return answer;
    }

    public void setAnswer(String answer) {
        this.answer = answer;
    }

    public int getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(int sortOrder) {
        this.sortOrder = sortOrder;
    }

    public InitiativeProfileQuestion getInitiativeProfileQuestion() {
        return initiativeProfileQuestion;
    }

    public void setInitiativeProfileQuestion(InitiativeProfileQuestion initiativeProfileQuestion) {
        this.initiativeProfileQuestion = initiativeProfileQuestion;
    }
}

InitiativeProfileQuestionRepository.java:

public interface InitiativeProfileQuestionRepository extends JpaRepository<InitiativeProfileQuestion, Long> {

    @Query("select ipa from InitiativeProfileQuestion ipa join fetch ipa.answers")
    public List<InitiativeProfileQuestion> getAllQuestions();
}

InitiativeProfileService.java:

@Service
public class InitiativeProfileService {

    @Autowired
    private InitiativeProfileQuestionRepository initiativeProfileQuestionRepository;

    public List<InitiativeProfileQuestion> getAllQuestions() {
        return initiativeProfileQuestionRepository.findAll();
    }

    public List<InitiativeProfileQuestion> getAllQuestionsFetch() {
        return initiativeProfileQuestionRepository.getAllQuestions();
    }

}

BaseController.java:

@RestController
@RequestMapping("/api")
public class BaseController {

    @Autowired
    InitiativeProfileService initiativeProfileService;

    @RequestMapping("/question")
    public List<InitiativeProfileQuestion> getQuestions() {
        return initiativeProfileService.getAllQuestions();
    }

    @RequestMapping("/questionFetch")
    public List<InitiativeProfileQuestion> getQuestionsFetch() {
        return initiativeProfileService.getAllQuestionsFetch();
    }
}

在我的BaseController中调用getQuestions()会返回一个&#34;无法初始化代理 - 没有会话&#34;错误。但是,在我的BaseController中调用getQuestionsFetch()加载就好了。

我希望它以一种方式工作,如果我调用getQuestions(),该对象将返回NO答案(因为延迟加载的对象不会在任何地方被调用)。但是,它只是给我一个错误。如果我正在使用联接提取进行查询,它也会通过显示答案(预期行为)来工作。

我做错了什么?我在不同的地方试过@Transactional而没有运气。我也没有.xml文件 - 到目前为止所有内容都是使用注释完成的。

我得到的错误是:

exception

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"])
    org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:238)
    org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:208)
    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:161)
    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101)
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:185)
    org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause

com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"])
    com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
    com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:177)
    com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:187)
    com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:647)
    com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:558)
    com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:145)
    com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
    com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
    com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183)
    com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:128)
    com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:1902)
    org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:231)
    org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:208)
    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:161)
    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101)
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:185)
    org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

2 个答案:

答案 0 :(得分:0)

对于延迟加载的例外,您必须尝试在会话外获取关联的对象。将延迟加载更改为急切或将您的代码放入会话中获取关联对象。 例如:

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.

答案 1 :(得分:0)

正如您从堆栈跟踪中看到的,当Jackson试图访问延迟加载的对象以将其序列化为JSON时,会发生错误。此时,spring事务已经完成,Hibernate会话关闭,这就是Hibernate无法再加载该对象的原因。

如果您不打算将该字段序列化,则可以使用@JsonIgnoreSpring's Jackson Serialization View Support