2011-01-25 14 views
10

私はマルチスレッドサーバーを作成しようとしています。問題は次のエラーが発生することです。 play.exceptions.JPAException:JPAコンテキストが初期化されていません。 JPA Entity Managerは、@ javax.persistence.Entityアノテーションで注釈付けされた1つ以上のクラスがアプリケーション内に見つかると自動的に開始します。私は何をしようとしていることは、新しいスレッドからDBにアクセスしているJPAとスレッドは、再生フレームワーク

ここにコード

package controllers; 
import java.util.Iterator; 
import java.util.List; 
import models.Ball; 


public class MainLoop extends Thread { 

@Override 
public void run() { 
    List<Ball> balls; 
    new Ball(5,5,2,2,10,15); 
    while (true){ 
     balls = Ball.all().fetch(); //Here throws an exception 

     for (Iterator iterator = balls.iterator(); iterator.hasNext();) { 
      Ball ball = (Ball) iterator.next(); 
      ball.applyForces(); 
     } 
    } 
} 
} 

は、任意のアイデアですか?

答えて

12

代わりにジョブを使用し、プレーンなスレッドを使用しないでください:

@OnApplicationStart 
public class MainLoop extends Job { 
     public void doJob() { 
       new BallJob().now(); 
     } 
} 

そしてBallJob:

public class BallJob extends Job { 
public void doJob() { 
    List<Ball> balls; 
    new Ball(5,5,2,2,10,15); 
    while (true){ 
     balls = Ball.all().fetch(); 
     for (Iterator iterator = balls.iterator(); iterator.hasNext();) { 
      Ball ball = (Ball) iterator.next(); 
      ball.applyForces(); 
     } 
    } 
} 
1

私は、あなたのスレッドがJPAエンティティマネージャを起動する機会を得る前に開始されていると推測しています。

Modelクラスに@Entityアノテーションが付いている場合は、エンティティマネージャが作成されていてエラーが表示されません。

だから、いくつかのオプションがあります。

  1. Play標準プラグインは、Play標準のonApplicationStartプロセスよりも低い優先度で作成できます。
  2. ブートストラップジョブからスレッドをキックスタートすることができます。これにより、サーバーとの対話を開始する前に、Playが正しく起動する機会が確保されます。 http://www.playframework.org/documentation/1/jobs#concepts
  3. 個人的に

を参照して、ブートストラップ・ジョブの詳細を表示するには、私はそれを文書化し、再生するプラグインはより多くのフレームワークを拡張するのではなく、処理の順序を変更するために意図されている方が良いオプション2となるだろう。

4

更新

これは、以下の何よりもすっきりです:

JPAPlugin.startTx(false); 
// Do your stuff 
JPAPlugin.endTx(false); 

今日も同様の問題がありました。

あなたは、スレッドごとに新しいEntityManagerし、トランザクションを作成し、JPAクラスでそれを設定する必要があります。

プレイは、それがにJPAEntityManagerを保つためだThreadLocalを使用していますので、それはあなたの作成したスレッドの場合はnullです。残念ながらJPAのヘルパーメソッドを使用することはできません(パッケージはプライベート)ので、ThreadLocalを直接使用する必要があります。ここでは、これを行うことができます方法は次のとおりです。

class Runner extends Runnable { 
    @Override 
    public void run() { 
     if (JPA.local.get() == null) { 
      EntityManager em = JPA.newEntityManager(); 
      final JPA jpa = new JPA(); 
      jpa.entityManager = em; 
      JPA.local.set(jpa); 
     } 

     JPA.em().getTransaction().begin(); 
     ... DO YOUR STUFF HERE ... 
     JPA.em().getTransaction().commit(); 
    } 
} 

私は何の問題もなくjava.util.concurrentのからシングルスレッド実行プログラムとそれを使用しています。

+2

更新:すべてのJPAの内容を削除し、JPAPlugin.startTxとJPAPlugin.closeTxに置き換えることができます。 –

+0

あなたのコメントを編集してコメントを追加しました。 – ripper234

+0

JPA.localをplay framework 1.4で操作するには、完全に変更されます。 – javaboygo

関連する問題