2011-01-25 101 views
10

我想創建一個多線程服務器。問題是我收到以下錯誤: play.exceptions.JPAException:JPA上下文未初始化。如果在應用程序中找到使用@ javax.persistence.Entity批註註釋的一個或多個類,則JPA實體管理器將自動啓動。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

我猜你的線程是在Play有機會啓動JPA實體管理器之前啓動的。

如果您的Model類用@Entity註釋,那麼實體管理器將會被創建,並且您的錯誤不會出現。

所以,你有幾個選項。或者,

  1. 您可以創建PlayPlugin,其優先級低於Play標準onApplicationStart進程。
  2. 您可以從啓動作業中啓動您的線程。這將確保Play在開始與服務器交互之前有機會正確啓動。要了解更多關於自舉作業,請參閱http://www.playframework.org/documentation/1/jobs#concepts

就個人而言,我會選擇2。

4

更新

這比什麼是下面整潔:

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

今天有類似的問題。

您必須爲每個線程創建新的EntityManager和事務,並將其設置爲JPA類。

Play使用ThreadLocal以保持其EntityManager JPA,所以它是空爲你創建的線程。不幸的是,您不能使用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替換它。 – 2012-09-05 08:58:29