[英]JPA and Threads in play framework
I'm trying to create a multithreading server. 我正在尝试创建一个多线程服务器。 The problem is that I get the following error: play.exceptions.JPAException: The JPA context is not initialized.
问题是我收到以下错误: play.exceptions.JPAException:JPA上下文未初始化。 JPA Entity Manager automatically start when one or more classes annotated with the @javax.persistence.Entity annotation are found in the application.
当在应用程序中找到使用@ javax.persistence.Entity批注注释的一个或多个类时,JPA实体管理器会自动启动。
What I'm trying to do is access the db from the new thread here's the code 我要做的是从新线程访问数据库这里是代码
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();
}
}
}
}
Any ideas? 有任何想法吗?
Don't use plain thread, use jobs instead : 不要使用纯线程,而是使用job:
@OnApplicationStart
public class MainLoop extends Job {
public void doJob() {
new BallJob().now();
}
}
And BallJob : 和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();
}
}
}
Update 更新
This is neater than what's below: 这比下面的内容更整洁:
JPAPlugin.startTx(false);
// Do your stuff
JPAPlugin.endTx(false);
Had similar problem today. 今天有类似的问题。
You have to create new EntityManager
and transaction for each thread and set it in JPA class. 您必须为每个线程创建新的
EntityManager
和事务,并在JPA类中设置它。
Play uses ThreadLocal
to keep it's EntityManager
in JPA , so it's null for your created thread. Play使用
ThreadLocal
将它的EntityManager
在JPA中 ,因此对于您创建的线程它是null。 Unfortunately you cannot use helper methods in JPA to do it (they are package private) and you have to use ThreadLocal
directly. 遗憾的是,您无法在JPA中使用帮助程序方法(它们是包私有),您必须直接使用
ThreadLocal
。 Here's how you can do this: 这是你如何做到这一点:
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();
}
}
I use it with single thread executor from java.util.concurrent without any problems. 我使用java.util.concurrent中的单线程执行器没有任何问题。
I am guessing your thread is kicked off before Play has a chance to start the JPA Entity Manager. 我猜你的线程在Play有机会启动JPA实体经理之前就开始了。
If your Model class is annotated with @Entity, then the entity manager would have been created and your error would not appear. 如果您的Model类使用@Entity注释,那么将创建实体管理器并且不会出现您的错误。
So, you have a couple of options. 所以,你有几个选择。 Either,
要么,
Personally, I would go with option 2. It is better documented, and play plugins are meant more for extending the framework rather than changing the order of processing. 就个人而言,我会选择选项2.更好的文档记录,播放插件更多的是扩展框架而不是改变处理顺序。
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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.