Не просто дайте код как решение, но и объясните его.

аюсь создать многопоточный сервер. Проблема в том, что я получаю следующую ошибку:play.exceptions.JPAException: контекст JPA не инициализирован. JPA Entity Manager автоматически запускается, когда в приложении обнаруживается один или несколько классов, аннотированных аннотацией @ javax.persistence.Entity.

То, что я пытаюсь сделать, это получить доступ к БД из нового потока вот код

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();
        }
    }
}
}

Есть идеи?

Ответы на вопрос(4)

что ваша тема будет запущена до того, как у Play появится шанс запустить JPA Entity Manager.

Если ваш класс Model помечен @Entity, то менеджер сущностей был бы создан, и ваша ошибка не появилась бы.

Итак, у вас есть несколько вариантов. Или,

Вы можете создать PlayPlugin с более низким приоритетом, чем стандарт Play в процессах ApplicationStart.Вы можете начать свою работу с начальной загрузки. Это обеспечит правильную загрузку Play перед началом взаимодействия с сервером. Чтобы узнать больше о заданиях начальной загрузки, см.http://www.playframework.org/documentation/1/jobs#concepts

Лично я бы выбрал вариант 2. Он лучше задокументирован, и игровые плагины предназначены скорее для расширения инфраструктуры, а не для изменения порядка обработки.

Обновить

Это аккуратнее, чем то, что ниже:

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 без проблем.

 ripper23402 дек. 2012 г., 18:47
Я отредактировал ваш ответ, чтобы включить ваш комментарий.
 Marek Piechut05 сент. 2012 г., 10:58
Обновление: вы можете удалить все файлы JPA и заменить их на JPAPlugin.startTx и JPAPlugin.closeTx.
 javaboygo14 нояб. 2017 г., 10:04
Как работать с JPA.local с play framework 1.4?, Меняется полностью
class Runner extends Runnable {
     @Override
     public void run() {
        EntityManager em = JPA.newEntityManager();
        em.setFlushMode(FlushModeType.COMMIT);
        JPA jpa = new JPA();
        jpa.bindForCurrentThread(JPA.DEFAULT, em, false);

         em.getTransaction().begin();
        // ... DO YOUR STUFF HERE ...
         em.getTransaction().commit();
     }
}
 Partho6313 февр. 2019 г., 07:27
Не просто дайте код как решение, но и объясните его.
Решение Вопроса

@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();
        }
    }
}

Ваш ответ на вопрос