Is calling method of EntityManager in a container-managed transaction context inside Servlet thread-safe?

52 Views Asked by At

There is the following code snippet inside a 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 methods are invoked inside container-managed transaction bounday => Question: is there any problem when calling the runTransaction() inside the doPost method? esp. is calling of runTransaction() thread-safe? If this approach is problematic, how to resolve?

1

There are 1 best solutions below

2
Paulo Araújo On

In your case, it may be thread-safe (cause it is request dependent), but it certainly is not transactional. @Transactional annotation activates transactions boundaries only when there is a "business method invocation" as defined by item 2.6.2 of CDI spec. In your case, servlet's doPost is calling a method inside its own class, so it will not be intercepted.

To be able to start the transaction, you should move the database code (entitymanager injection and runTransaction method) to another CDI bean (you may choose a @RequestScoped to be thread-safe) and call that bean from your servlet. So:

@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
    }
}

As dataManager is a @RequestScoped CDI proxy, each time a call is made to it, the proper request context bean will be called, making it request dependent and thread-safe. Note that data sharing between beans may interfere the thread-safiness of the execution, so choose what you pass to runTransaction method wisely.