Spring MVC 3.1.2 + Jackson 2:懒惰初始化集合时的LazyInitializationException - 没有关闭会话或会话

时间:2012-11-25 19:55:45

标签: json spring hibernate hql jackson

我对使用Spring MVC 3.1.2和Jackson 2的错误感到疯狂。

我有以下模特类:

@Entity
@Table(name = "USER")
@JsonIgnoreProperties(ignoreUnknown=true)
public class User implements Serializable
{
    @Id
    @SequenceGenerator(name = "USER_ID", sequenceName = "USER_ID_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_ID")
    private Long id;

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

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

    @ManyToMany
    @JoinTable(name = "FRIENDS",
        joinColumns = @JoinColumn(name = "personId"),
        inverseJoinColumns = @JoinColumn(name = "friendId")
    )
    @JsonManagedReference
    private List<User> friends;

    @ManyToMany
    @JoinTable(name="FRIENDS",
        joinColumns=@JoinColumn(name="friendId"),
        inverseJoinColumns=@JoinColumn(name="personId")
    )
    @JsonIgnore
    private List<User> friendOf;

    // Other attributes and methods... 
}

当我获得一个用户的单个实例时,它被Jackson正确序列化。但是当我尝试获取包含朋友的User实例时,会抛出以下异常:

  

org.hibernate.LazyInitializationException:懒得初始化   角色集合:com.frooid.model.User.friends,没有会话或   会议已结束

我使用单个HQL获取此实例:

select u from User u left join fetch u.friends f where u.id = :id

感谢大家!

3 个答案:

答案 0 :(得分:5)

尝试使用OpenSessionInViewFilter虽然这是为了访问视图中的延迟初始化字段,但可以让会话保持开放状态,以便Jackson能够访问该集合。

OpenSessionInViewFilter将Hibernate会话绑定到线程以进行整个请求处理。用于“视图中的开放会话”模式,即允许在Web视图中延迟加载,尽管原始事务已经完成。

在Web.xml中

<filter>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

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

API Documentation

答案 1 :(得分:5)

默认情况下,ToMany关联是延迟加载的。这意味着在调用friends列表的方法时,只会从数据库加载用户的文本。

这种延迟加载只能在用于加载用户的会话打开时发生。因此,如果您在没有加载好友列表的情况下从事务方法返回用户,则会话将被关闭,并且尝试加载freinds列表将导致您获得的异常。

因此,如果客户端需要加载freinds列表,则使用HQL获取朋友,或者通过调用列表上的方法或调用{{1}强制在服务方法内部对列表进行初始化}。

编辑:既然您在HQL中有一个提取,它应该可以工作。另一个问题是双向关联被映射两次:一次在Hibernate.initialize(user.getFriends())字段上,一次在friends字段上。其中一个关联必须使用friendOf属性标记为另一个关联:

mappedBy

答案 2 :(得分:0)

我有类似的问题。方法是创建一个新类(视图),并在@JsonView({NewClass1.class,NewClass2.class})中的每个属性上添加此类,在定义属性的实体中。您可以选择要作为响应的一部分加载的变量,并将该类包含在@JsonView中。就这么简单!