假设在应用程序中,您有一个名为 User 的实体。每个用户可以拥有许多使用延迟获取加载的文章。
@Entity
@Table(name = "Users")
public class User {
private Integer id;
private Set<Article> articles = new HashSet<Article>();
...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
public Set<Article> getArticles() {...}
}
在 Web 服务端,我想通过 Id 加载用户并将其传递给球衣 Viewable JSP 以返回和显示。我还想为每个请求使用一个会话。
@GET
public Response getUser() {
Session session = getSessionFactory().openSession();
session.beginTransaction();
User user = (User) session.getNamedQuery("getUserById").setInteger("id", 1).uniqueResult();
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("user", user);
Viewable v = new Viewable("/user", dataMap);
Response r = Response.ok(v).build();
session.getTransaction().commit();
session.close();
return r;
}
在 user.jsp 中,我想访问文章并将它们打印出来。
<c:forEach var="a" items="${it.user.articles}">
<span>${a.title}</span>
</c:forEach>
运行此代码并尝试请求 JSP 最终会引发异常:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: my.package.User.articles, no session or session was closed
发生这种情况是因为显然创建 Viewable、将其传递给 ResponseBuilder 并调用 build() 实际上并没有创建 JSP。在我的方法返回并且会话已关闭之后,JSP 将在更远的地方创建。
一个明显的选择是将文章的获取类型设置为 eager,但这并不理想,因为在大多数情况下,当我使用 User 对象时,我不需要加载或显示文章。
有没有办法在我的方法返回之前强制 jersey 解释和构造 jsp?是否有某种 onResponse 或 postResponse 侦听器可以传递我的代码来关闭会话?
一般来说,我在处理打开/关闭休眠会话的方式上应该做些什么不同的事情?从谷歌搜索来看,每个请求一个会话似乎是大多数人提倡使用的,所以我想我会尝试一下。