在Servlet内的容器管理事务上下文中调用EntityManager的方法是线程安全的吗?

问题描述 投票:0回答:1

servlet

中有以下代码片段
@PeristenceContext
private EntityManager entityManager;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
           throws ServletException,
                  IOException {
    runTransaction();
}
@Transactional
public void runTransaction() {
   entityManager.merge(entityA);
   entityManager.remove(entityC);
}

entityManager
方法是在容器管理的事务边界内部调用的=>问题:在
runTransaction()
方法内部调用
doPost
有什么问题吗?尤其是
runTransaction()
的调用是线程安全的吗?如果这种方法有问题,如何解决?

jpa jakarta-ee entitymanager jta
1个回答
1
投票

在您的情况下,它可能是线程安全的(因为它依赖于请求),但它肯定不是事务性的。仅当存在 CDI 规范

第 2.6.2 项定义的“业务方法调用”时,
@Transactional 注释才会激活事务边界。在你的例子中,servlet的doPost正在调用它自己的类中的方法,所以它不会被拦截。

为了能够启动事务,您应该将数据库代码(entitymanager 注入和 runTransaction 方法)移动到另一个 CDI bean(您可以选择

@RequestScoped

 来保证线程安全)并从 servlet 调用该 bean。所以:

@RequestScoped public class DataManager { @PersistenceContext private EntityManager em; @Transactional public void runTransaction(...) { // Do your thing here } } @WebServlet("/save") public class YourServlet extends HttpServlet { @Inject private DataManager dataManager; protected void doPost(HttpServletRequest req, HttpServletResponse resp) { // Gather data to be saved dataManager.runTransaction(/*arguments*/); // transaction will be started just before this method is actually called and will end before returning the result to this method // return response using resp } }
由于 

dataManager

 是一个 
@RequestScoped
 CDI 代理,每次调用它时,都会调用正确的请求上下文 bean,使其具有请求相关性和线程安全性。请注意,bean 之间的数据共享可能会干扰执行的线程安全性,因此请明智地选择传递给 
runTransaction
 方法的内容。

© www.soinside.com 2019 - 2024. All rights reserved.