我在JEE CDI应用程序的业务层中有一项服务,需要执行需要在单独的线程上生成的密集型工作任务。
public MyService {
public void doTask( MyDataKey myDataKey ) {
MyThread myThread = new MyThread( myDataKey );
myThread.run();
}
}
public MyThread : extends Thread {
MyDataKey myDataKey;
...
public MyThread( MyDataKey inMyDataKey ) {
this.myDataKey = inMyDataKey;
}
public void run() {
...
myWorkerService.doWork( this.myDataKey );
}
}
public MyWorkerService {
@PersistenceContext( unitName = "default" ) EntityManager em;
...
@Transactional
public void doWork( MyDataKey myDataKey ) {
MyData myData = em.find( myDataKey.getId() );
myData.setStatus( "Changed" );
... (Set values for other properties)
MyDataChild myDataChild = new MyDataChild( "Some Value" );
em.persist( myDataChild );
myData.addChild( myDataChild );
// According to documentation, flush should update myData
// and em.merge( myData ) is not needed.
}
// When doWork() is exited, the transaction should commit the changes
// to MyData upon EM flush.
}
我需要能够使用EntityManager来保存与MyData相关的新元素并更新MyData属性。奇怪的是,em.persist(myDataChild)工作并且存储了新的数据元素,但是不保留对它的引用和对myData属性的更改。
我遇到的问题是如何使用CDI注入WorkerService以获取MyThread类中run()操作范围内的EntityManager的访问权。
如果我在MyService中创建MyWorkerService并将其传递给线程,则EM flush显然不起作用,以便在退出@Transactional方法并且MyThread.run()完成后不保留对MyData属性的更改
例如:
public MyService {
@Inject MyWorkerService myWorkerService;
...
public void doTask( MyDataKey myDataKey ) {
MyThread myThread = new MyThread( myWorkerService, myDataKey );
myThread.run();
}
}
public MyThread : extends Thread {
MyWorkerService myWorkerService;
MyDataKey myDataKey;
...
public MyThread( MyWorkerService inMyWorkerService, MyDataKey inMyDataKey ) {
this.myWorkerService = inMyWorkerService;
this.myDataKey = inMyDataKey;
}
public void run() {
...
myWorkerService.doWork( this.myDataKey );
}
}
以上代码是实际代码的简化版本
这似乎发生的问题是,因为MyWorkerService是在线程run()上下文之外注入的,并且EntityManager类似地在父服务上下文中创建,所以当在EntityManager中使用EntityManager时会出现一些问题。在run()上下文中执行的@Transactional worker操作以及对MyData的更改不会传播到DB,也不会被MyData实例保留。
以下是我正在寻求答案的问题:
1)将MyWorkerService传递给MyThread(如上所示)是设置工作服务和EntityManager以在thread.run()中使用的可行方法吗?即确保每个人注射CDI。
2)为什么@Transactional doWork()操作中对MyData实例的更改没有保留或存储?
3)有没有更好的方法在thread.run()操作的上下文中获取EntityManager,以确保更好的线程安全使用?
4)需要更改哪些代码才能以线程安全的方式工作,并在thread.run()调用中正确使用EntityManager和@Transactional?
答案 0 :(得分:0)
Java EE不鼓励使用创建线程,原因很多! Java EE是关于托管对象的, 所以不应该尝试创建和管理线程之类的对象 !
幸运的是,您并不是第一个需要执行此类任务的人。您可以选择多种方式进行工作,并处于托管环境中,您的注射仍然有效。以下是一些更常见的内容:
ManagedExecutorService
。看看这个:https://martinsdeveloperworld.wordpress.com/2014/02/25/using-java-ees-managedexecutorservice-to-asynchronously-execute-transactions/