2016-06-16 5 views
0

私は、これが私のアプリケーションで同じようにそれらをチュートリアルで使用している: http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/ジャージー、Guiceのと休止状態 - のEntityManagerスレッドセーフ

私のアプリは、多くの同時要求を受信し、データベースへの更新を行いますJAX-RS Webサービスです。

GenericDAOImpl.java実装:

public class GenericDAOImpl<T> implements GenericDAO<T> { 

    @Inject 
    protected EntityManager entityManager; 

    private Class<T> type; 

    public GenericDAOImpl(){} 

    public GenericDAOImpl(Class<T> type) { 
     this.type = type; 
    } 

    @Override 
    public void save(T entity) { 
     entityManager.getTransaction().begin(); 
     entityManager.persist(entity); 
     entityManager.getTransaction().commit(); 
    } 

}

2つの同時実行スレッドは、エンティティを保存しようとすると、私はトランザクションをコメントする場合

java.lang.IllegalStateException: Transaction already active 

の保存がうまく機能し得ます。

私は

@Inject 
protected Provider<EntityManager> entityManagerProvider; 

または

@Inject 
protected EntityManagerFactory entityManagerProvider; 

と要求ごとに使用しようとしました:

EntityManager entityManager = entityManagerProvider.get() 

しかし、その後、私は得る:

org.hibernate.PersistentObjectException: detached entity passed to persist 

Guice + Hibernate EntityManagerインジェクション/スレッドセーフ汎用DAOクラスを実装する正しい方法は何ですか? http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/

から

UPDATE

アンドリュー・レイナーのコメントは、「ロジックは本当に生産準備ができていない - Webアプリケーションで使用される少なくとも場合

休止状態の接続プールは非常に基本的なものです。生産準備ができていません - c3p0などのデータソースプールを使用することをお勧めします。

EntityManagerは再利用されません - トランザクション/リクエストごとに作成されることを意図しています。後続の要求を汚染する可能性があります。

何か問題が発生した場合でもトランザクションのロールバックはありません。

興味深いアプローチ - 。それはGuicesがEntityManangerインスタンスと取引のライフサイクルを管理するための拡張モジュールを永続自身の使用するWebアプリケーションのためのより安全だろう」

答えて

0

問題は、それが同時呼び出し中に同じEntityManagerを再利用するので、私のエンドポイントは@Singletonで注釈されたということでした。 @Singletonを削除した後、同時呼び出し中に、異なるEntityManagerオブジェクトが使用されます。エンドポイント呼び出しが後続する場合は、前の/古いEntityManagerが使用される可能性があります。

非常に簡単な例:

@Path("/v1/items") 
public class ItemsService { 

    @Inject 
    private EntityManager entityManager; 

    @POST 
    @Path("/{id}") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public void saveItem(){ 
     entityManager.getTransaction().begin(); 
     entityManager.persist(new Item()); 
     entityManager.getTransaction().commit(); 
    } 
} 
0

まず第一に、あなたはEntityManagerのどのような種類のを使用していますか?私はこの種のsuposseあなたのコードを見てみると、あるアプリケーション管理のEntityManagerあなたがのEntityManagerの種類を理解することが重要であろう

は参照してください:。。この上http://docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html

ベイシングは、あなたがてEntityManagerFactoryを作成する必要がありますオブジェクトEntityManagerオブジェクトを作成します。

基本例:

private static EntityManagerFactory emf; 
EntityManager em = null; 

public static EntityManagerFactory getEmf(){ 
    if(emf == null){ 
     emf = Persistence.createEntityManagerFactory("nameOfYourPersistenceUnit"); 
    } 
    return emf; 
} 


em = getEmf().createEntityManager(); 
em.getTransaction().begin(); 
em.persist(entity); 
em.getTransaction().commit(); 
em.close(); 
+0

を助ける方法は公共のEntityManager provideEntityManagerを@Provides(のEntityManagerFactoryのEntityManagerFactory ) "スレッドごとに1つのエンティティマネージャを持つために、ここでThreadLocalストレージを使用します。"それはhttp://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/に記載されています – Justas

0

それは、トランザクションが、それは別のプロセスによって開かれたと閉じられていないことを意味し、既に開いていると言うなら...

私が使用することをお勧め@Transactionl代わりに、ライティングの:

em.getTransaction().begin(); 

em.getTransaction().commit(); 
em.close(); 
あなたのために物事を管理します

...

をので、あなたのために、それはこのようになります:

@Transactionl 
@POST 
@Path("/{id}") 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
public void saveItem(){ 
    entityManager.persist(new Item()); 
} 

希望者は、私が持っている