没有懒惰地初始化一个集合

时间:2012-03-20 21:58:58

标签: spring hibernate jpa

我正在为我的数据库开发一个安静的Web服务。我正在使用jpa从数据库中恢复数据并为结构体提供弹簧。我已经使用基本的dao查询(findById,save ...)测试了这个架构,它运行得很好。然后在dao实现中我添加了一个新方法,它基本上执行一个直接在mysql db上测试的查询(并且它有效)

public List<PositionHistory> findByFavUserGBuser(Integer favoriteUserId,
        Integer pageNumber, Integer rowsPerPage, String usernameFilter) {
    String queryString="" +
            "SELECT ph.* " +
            "FROM user u, position_history ph, spot s " +
            "WHERE " +
                "ph.date IN (SELECT MAX(ph2.date) FROM position_history ph2 GROUP BY ph2.user_iduser) and " +
                "s.id_spot=ph.spot_idspot and " +
                "u.id_user=ph.user_iduser and  ";

    if (usernameFilter!=null)
        queryString+="u.username like '%:usernameFilter%' and ";

    queryString+="" +
                "ph.user_iduser IN (SELECT ALL fu.user_iduserto FROM favorite_user fu WHERE fu.user_iduserfrom=:favoriteUserId) " +
            "GROUP BY ph.user_iduser " +
            "LIMIT :startLimit,:rowsPerPage";

    Query query = entityManager.createNativeQuery(queryString,PositionHistory.class);
    query.setParameter("favoriteUserId", favoriteUserId);
    query.setParameter("startLimit", pageNumber*rowsPerPage);
    query.setParameter("rowsPerPage", rowsPerPage);

    if (usernameFilter!=null)
        query.setParameter("usernameFilter", usernameFilter);

    return query.getResultList();
}

然后我创建了一个控制器来检索数据,如下所示:

@Controller
@Transactional
public class MyController {

    @Autowired
    public DaoPositionHistory dph;

    @Transactional
    @RequestMapping(value = "/getData/{id}/", method = RequestMethod.POST)
    @ResponseBody
    public List<PositionHistory> home(@PathVariable int id) {
        List<PositionHistory> resultlist=(List<PositionHistory>) dph.findByNearestPositionGBuser(id, 0, 10, null, null, null);
        return resultlist;
    }
}

但是当我调用该服务时,我收到以下错误:

ERROR: org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: com.windy.spring.data.User.favoriteSports, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.windy.spring.data.User.favoriteSports, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)
    at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:272)
    at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:45)
    at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23)
    at org.codehaus.jackson.map.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:86)
    at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
    at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
    at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
    at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
    at org.codehaus.jackson.map.ser.std.StdContainerSerializers$IndexedListSerializer.serializeContents(StdContainerSerializers.java:122)
    at org.codehaus.jackson.map.ser.std.StdContainerSerializers$IndexedListSerializer.serializeContents(StdContainerSerializers.java:71)
    at org.codehaus.jackson.map.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:86)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1613)
    at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:142)
    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:179)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:81)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:94)
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:73)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Unknown Source)

如果我将这个方法声明为@transactional,我无法理解为什么会出现此错误?关于如何解决问题的任何想法?

这也是我的用户类

@XmlRootElement
@Entity
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id_user")
    private int idUser;

    private String cellphone;

    private String email;

    @Lob()
    private byte[] foto;

    private String name;

    private String notes;

    private String password;

    private String surname;

    private String username;

    //bi-directional many-to-one association to FavoriteSport
    @OneToMany(mappedBy="user")
    private List<FavoriteSport> favoriteSports;

    //bi-directional many-to-one association to FavoriteSpot
    @OneToMany(mappedBy="user")
    private List<FavoriteSpot> favoriteSpots;

    //bi-directional many-to-one association to FavoriteUser
    @OneToMany(mappedBy="user2")
    private List<FavoriteUser> favoriteUsers;

    //uni-directional many-to-one association to Role
    @ManyToOne
    @JoinColumn(name="role_idrole")
    private Role role;

    //bi-directional many-to-one association to UserAccount
    @OneToMany(mappedBy="user")
    private List<UserAccount> userAccounts;

    public User() {
    }

    public int getIdUser() {
        return this.idUser;
    }

    public void setIdUser(int idUser) {
        this.idUser = idUser;
    }

    public String getCellphone() {
        return this.cellphone;
    }

    public void setCellphone(String cellphone) {
        this.cellphone = cellphone;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public byte[] getFoto() {
        return this.foto;
    }

    public void setFoto(byte[] foto) {
        this.foto = foto;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNotes() {
        return this.notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSurname() {
        return this.surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List<FavoriteSport> getFavoriteSports() {
        return this.favoriteSports;
    }

    public void setFavoriteSports(List<FavoriteSport> favoriteSports) {
        this.favoriteSports = favoriteSports;
    }

    public List<FavoriteSpot> getFavoriteSpots() {
        return this.favoriteSpots;
    }

    public void setFavoriteSpots(List<FavoriteSpot> favoriteSpots) {
        this.favoriteSpots = favoriteSpots;
    }

    public List<FavoriteUser> getFavoriteUsers() {
        return this.favoriteUsers;
    }

    public void setFavoriteUsers(List<FavoriteUser> favoriteUsers) {
        this.favoriteUsers = favoriteUsers;
    }

    public Role getRole() {
        return this.role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public List<UserAccount> getUserAccounts() {
        return this.userAccounts;
    }

    public void setUserAccounts(List<UserAccount> userAccounts) {
        this.userAccounts = userAccounts;
    }

}

3 个答案:

答案 0 :(得分:2)

我通过阅读你问题的其他答案来解决这个问题。以防任何人需要它是一个例子:

@Override
public OriginServer get(Integer id){
    OriginServer server = (OriginServer) sessionFactory
        .getCurrentSession().get(OriginServer.class, id);
    Hibernate.initialize(server.getPools());
    return server;
}   

在此示例中,'getPools'是来自OriginServer的@OneToMany关系。

答案 1 :(得分:1)

堆栈跟踪清楚地显示在控制器方法完成(并且事务已关闭)之后发生异常。

因此要么使用扩展持久化上下文(其中会话比事务长寿命),在控制器方法返回之前访问延迟集合,修改DAO或映射以急切加载集合,或者不返回包含该集合的对象

答案 2 :(得分:0)

您的错误是因为您没有在DAO中初始化实体关联,然后Jackson转换器正在尝试将返回对象中的所有关联转换为JSON。由于关联未初始化,因此错误被抛出,因为Controller没有Hibernate Session的句柄。

请在此处查看我的答案,了解如何纠正:Spring @ResponseBody Json Cyclic Reference