1

アプリケーションに 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 でユーザーをロードし、それを jersey 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 は、メソッドが返されてセッションが閉じられた後、さらに下のどこかに作成されます。

明らかなオプションの 1 つは、記事のフェッチ タイプを熱心に設定することですが、ほとんどの場合、User オブジェクトを使用しているときに記事を読み込んだり表示したりする必要がないため、これは理想的ではありません。

メソッドが戻る前に jersey に jsp の解釈と構築を強制する方法はありますか? セッションを閉じるためにコードを渡すことができる onResponse または postResponse リスナーはありますか?

一般的に、休止状態セッションの開始/終了を処理する方法とは異なる方法で行うべきことはありますか? グーグルで調べてみると、リクエストごとに1つのセッションを使用することをほとんどの人が推奨しているように見えるので、それを試してみようと思いました.

4

3 に答える 3

0

「ほとんどの場合、User オブジェクトを使用しているときに記事を読み込んだり表示したりする必要はありません」とあなたは言いますが、この場合、実際にはそのデータが必要であることは明らかです。これは、フェッチ戦略がほとんどの場合、マッピングで静的ではなく、ユースケースごとに適切に処理される方法の代表的な例です。

たとえば、ここでは、おそらくgetUserById名前付きクエリは次のようになります。

select u from User u where u.id = :id

代わりに、次のクエリを使用します (新しい名前付きクエリを作成するgetUserByIdWithArticles:

select u from User u join fetch u.articles where u.id = :id

各ユース ケースに必要なデータ量は、ほとんどの場合、ユース ケースによって異なります。適切な量​​のデータを取得することは、常にパフォーマンス向上への最善の道です。

于 2012-05-22T17:55:53.873 に答える
0

あなたが興味を持っているのは Open Session In View パターンのようですが、一部の人々はそれをアンチパターンと考えています。

于 2012-05-22T16:04:01.860 に答える
0

オープン セッション イン ビュー」アプローチは、まさにこの問題を解決する方法です。

もう 1 つの方法は、EJB または Spring を使用することです。その後、彼らはトランザクション処理を引き継ぎます。EJB は、JPAEntityManagerで使用する場合に完全に透過的に実行し、Spring はorg.springframework.orm.jpa.support.OpenEntityManagerInViewFilterこのためのフィルターを提供します。

コンテナーが EJB をサポートしている場合は、以下を作成します@Stateless

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public User find(Integer id) {
        return em.createNamedQuery("getUserById", User.class)
            .setParameter("id", id)
            .getSingleResult();
    }

}

次のように Web サービスで使用します。

@EJB
private UserService userService;

@GET
public Response getUser() {
    User user = userService.find(1);

    Map<String, Object> dataMap = new HashMap<String, Object>();
    dataMap.put("user", user);
    Viewable v = new Viewable("/user", dataMap);
    Response r = Response.ok(v).build();
    return r;
}

トランザクションや遅延フェッチについて心配する必要はもうありません。

于 2012-05-22T16:08:59.580 に答える