【问题标题】:Spring MVC 3.1.2 + Jackson 2: LazyInitializationException when lazily initialize a collection - no session or session was closedSpring MVC 3.1.2 + Jackson 2:延迟初始化集合时出现 LazyInitializationException - 没有会话或会话关闭
【发布时间】:2012-11-13 08:10:14
【问题描述】:

我因使用 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... 
}

当我得到一个 User 实例时,它被 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

谢谢大家!

【问题讨论】:

  • 您可以发布尝试访问该集合的代码吗?是在jsp还是控制器中访问集合?
  • 我使用 Spring MVC 访问它,通过控制器到服务,然后在 DAO 中。控制器通过 JQuery 使用 getJSON 方法访问。
  • 也许是个愚蠢的问题,但您的服务是否标有@Transactional?可以发一下你的服务方式吗?
  • 通过浏览器直接访问(如localhost:8084/frooid/app/user/get/17)没有好友的实例,我得到如下结果:{"id":17,"firstName":"Marcelo","lastName":"Juventino","email":"marcelo@frooid.com","password":"Whb8P4v086kKz2fQbQaDbqvrUZ8=","genre":"M","birth":340081200000,"urlPhoto":"http://...","thought":"Teste de envio de mensagem 8...","bio":"Esta eh a area reservada a bio...","friends":[]}当实例与好友相关时,出现异常。
  • @kmb385 我的服务方法如下:`@Transactional(readOnly=true) public User get(Long userId) { return userDAO.get(userId); } `

标签: json spring hibernate hql jackson


【解决方案1】:

尝试使用OpenSessionInViewFilter,虽然这用于访问视图中的惰性初始化字段,但它可能会保持会话打开,让 Jackson 能够访问集合。

OpenSessionInViewFilter 将 Hibernate Session 绑定到线程,用于请求的整个处理。用于“在视图中打开会话”模式,即允许在 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

【讨论】:

  • 嗨@kmb385!你的解决方案很棒!但是,由于模型中的自关系,抛出了 Stackoverflow 异常。你知道是否有某种方法可以限制杰克逊可以导航到停止序列化的级别?
  • 当我尝试使用这些过滤器时,我得到:“没有定义 [javax.persistence.EntityManagerFactory] ​​类型的合格 bean”。我是否需要提及我一般使用 Hibernate(不是 Persistence)?
【解决方案2】:

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

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

因此,如果客户端需要加载好友列表,则可以使用 HQL 获取好友,或者通过调用列表上的方法或调用 Hibernate.initialize(user.getFriends()) 在服务方法内部强制初始化列表。

编辑:因为您的 HQL 中有一个 fetch,所以它应该可以工作。另一个问题是双向关联被映射了两次:一次在friends 字段上,一次在friendOf 字段上。必须使用mappedBy 属性将其中一个关联标记为与另一个相反:

@ManyToMany(mappedBy = "friends")
@JsonIgnore
private List<User> friendOf;

【讨论】:

  • 不幸的是,这个解决方案不起作用。异常仍在发生... :(
  • 好的。现在想想,问题可能出在你有一个递归关联的事实:用户有朋友有朋友,有朋友等等。用户的序列化必须是可以的,但是杰克逊可能会尝试序列化朋友,以及他们的朋友等。你需要在某个地方切断这个过程。
  • 天啊@jb-nizet...你知道我该如何解决它吗?如果您有一些建议,包括模型的更改,我将不胜感激! :)
  • 不知道。我对杰克逊一无所知。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 2011-03-31
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-04-01
    相关资源
    最近更新 更多