2011-01-25 104 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