web-dev-qa-db-ja.com

JPA遅延読み込み

JPAエンティティの遅延読み込みプロパティに問題があります。私は多くの同様の質問を読みましたが、それらは春または冬眠に関連しており、彼らの不安は当てはまらないか、助けになりません。

アプリケーションは、Wildflyアプリケーションサーバーで実行されるJPA2.1を備えたJEEです。 DAOセッションBeanとそれをまとめるサーブレットの2つのエンティティがあります。

@Entity
@Table(name = "base_user")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    int id;

    @OneToMany(fetch=FetchType.LAZY, mappedBy="user")
    List<OAuthLogin> oauthLogins;

}


@Entity
@Table(name = "oauth_login")
public class OAuthLogin implements Serializable {
    @ManyToOne
    @JoinColumn(name="user_id", nullable=false)
    User user;
}


@Stateless(name = "UserDAOEJB")
public class UserDAO {
    @PersistenceContext(unitName="OAUTHDEMO")
    EntityManager em;

    public User findById(int id) {
        User entity;
    entity = em.find(User.class, id);
        return entity;
    }
}


public class SaveUserServlet extends HttpServlet {
    @EJB
    UserDAO userDAO;

    @Transactional
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = new User(name);
        user.setEmail(email);
        System.out.println("Persisting user " + user);
        userDAO.persist(user);

        OAuthLogin fbLogin1 = new OAuthLogin(user, OAuthProvider.FACEBOOK, "1501791394");
        loginDAO.persist(fbLogin1);

        User user2 = userDAO.findById(user.getId());
        List<OAuthLogin> oauthLogins = user2.getOauthLogins();

このコードを実行すると、次のように失敗します。

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cz.literak.demo.oauth.model.entity.User.oauthLogins, could not initialize proxy - no Session
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.Java:572)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.Java:212)
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.Java:551)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.Java:140)
org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.Java:294)
cz.literak.demo.oauth.servlets.SaveUserServlet.doPost(SaveUserServlet.Java:66)

WebLogic/JPA1で非常によく似たパターンを使用しましたが、スムーズに実行されました。何か案が?ありがとう

PS。これはJPAアプリケーションです。休止セッションなどはありません。

11
Leos Literak

使用できる代替手段はほとんどありません。

カスケード永続性を使用します。

@OneToMany(fetch=FetchType.LAZY, mappedBy="user", cascade = {CascadeType.PERSIST})
List<OAuthLogin> oauthLogins;

サーブレットで以下を実行します。

User user = new User(name);
user.setEmail(email);
OAuthLogin fbLogin = new OAuthLogin(user, OAuthProvider.FACEBOOK, "1501791394");      
user.getOauthLogins().add(fbLogin) // this is enough assuming uni-directional association
userDAO.persist(user);
List<OAuthLogin> oauthLogins = user.getOauthLogins();

これでうまくいくはずです。さらに、トランザクションが1つでJDBC呼び出しが少なくなります。

これは、特定のサーブレットメソッドを呼び出す特定のユースケースに役立ちます。

eJBのプリフェッチコレクション

public User findById(int id, boolean prefetch) {
    User entity = em.find(User.class, id);
    if (prefetch) {
        // Will trigger 1 or size JDBC calls depending on your fetching strategy
        entity.getOauthLogins().size() 
    }
    return entity;
}

または、 条件を使用してフェッチモードをオーバーライドする

これは、FetchType.LAZYを保持しながらOAuthLoginを使用してUserコレクションをフェッチし、その特定のコレクションのみのLazyInitializationExceptionを避けたい場合に役立ちます。

ビューフィルターでエンティティマネージャーを開くを使用する

Googleだけで、たくさんの例が見つかります

これにより、基本的に、LazyInitializationExceptionが、遅延してフェッチされるすべての関連付けごとに、クロスエンティティアプリケーションごとに防止されます。

PS:

  1. Springを使用していない場合、なぜ@Transactionalを使用しているのですか(デフォルトではHttpServletにも適用されません)
  2. おそらく何らかの調整されたソリューションを使用して、WebLogicで機能していました。
15
Ori Dar

LazyInitializationExceptionは、関連付けられたセッションが閉じられた後に遅延コレクションにアクセスすることを意味します。

コードが正常に見えると、問題はこの質問と同じになる可能性があります JPAおよびHibernateのLazyInitializationException

メソッドの最初にトランザクションが開かれていることを確認できますか?

3
Andreas Aumayr

JPAでlazeを初期化するには、jarライブラリを呼び出して起動する必要があります。mavenまたはmanual por exampleの場合は、lazeが必要な場合は、mavenでjarを使用します。
jar de.empulse.eclipselink 詳細http://wiki.Eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving#Use_the_Maven_plugin

1
GuapoSasa