1

To me (someone who is new to JavaEE development), I would think that a container managed EntityManager would be responsible for rolling back failed transactions and not a SessionContext instance. Suppose the following scenario...

@Stateless
public class MySessionBean implements MySessionBeanRemoteInterface {
    @PersistenceContext(unitName="MYPu")
    private EntityManager em;

    @Resource
    private SessionContext sctx;

    @Override
    public StackOverFlowUser createSOUser(String userName, int rep) {
         try {
             StackOverFlowUser su = new StackOverFlowUser();
             su.setUserName(stackOverflowName);
             su.setRep(rep);
             su.setIsBalusC(userName.equals("BalusC");
             su.setIsTheJonSkeet(userName.equals("jon skeet"));
             return em.merge(su);
         } catch (Exception e) {
             //sctx.setRollbackOnly();
             return null;
         }
    }

}

Why wouldn't the EntityManager be responsible for this? Why would SessionContext be used?

Rob L
  • 3,073
  • 6
  • 31
  • 61

1 Answers1

1

Because you told the container to manage transactions via JTA (transaction-type="JTA"), not JPA (transaction-type="RESOURCE_LOCAL"). JTA is in turn managed by EJB container. Hence the role of the SessionContext here.

But what bothers me, you're suppressing the exception and returning null. You'd better not do that in business service methods. You'd better let the exception go instead of returning null. The EJB container will in any exceptional case automatically perform the rollback. Get rid of the try-catch and return null in EJB and just have the EJB's client deal with the exception itself.

E.g.

try {
    mySessionBean.createSOUser(userName, rep);
} catch (PersistenceException e) {
    showSomeGlobalErrorMessage(e.getMessage());
}

Or, even better, just let it further go to the underlying container. E.g. if it's actually a servlet container:

<error-page>
    <exception-type>javax.persistence.PersistenceException</exception-type>
    <location>/WEB-INF/errorpages/db-fail.xhtml</location>
</error-page>

Or perhaps the MVC framework in question has even a customizable global exception handler for that. At least, JSF allows this opportunity, you could then globally set a faces message without the need to repeat the try-catch over all place in managed bean methods calling a service method.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Man, this is like getting an autograph from a celebrity! I found your answer very helpful. However, I am wondering what is the reason the EntityManager would not be responsible for rollbacks if it is in charge of persist, merge, remove, etc. To me (and maybe I am missing a concept here or not truly understanding the intended functionality of the EntityManager) it would seem like rollback would be one of the functions of the EntityManager. Is it because data from the Session is needed (due to container managed transactions) in order to rollback a transaction? – Rob L Jun 10 '15 at 18:30
  • 1
    It is, but when delegating to JTA, EJB takes over it so that you never need to worry about rollbacks. This way your code is more [DRY](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself). Or did you really intend to put a try-catch-rollback in every single service method? This defeats the job of EJB+JTA. See also the second "See also" link (and perhaps also the "See also" links therein). – BalusC Jun 10 '15 at 18:36
  • I did not intend to do that. However, the structure of the code I put above as the example is in an existing application I am working on. I personally would have done what you said and instead of returning null, I would have added a throws on the method and thrown the Exception back. Thank you for the guidance (and all of your tutorials I have been reading over the past several months). – Rob L Jun 10 '15 at 18:46
  • 1
    You're welcome :) You don't necessarily need to add a `throws` nor to throw an exception yourself. JPA will do it when the query returned an exceptional result. Unless JPA doesn't throw an exception in a case which is according to your business requirements exceptional. You're then of course free to throw a custom exception, as long as it's annotated with [`@ApplicationException(rollback=true)`](http://docs.oracle.com/javaee/7/api/javax/ejb/ApplicationException.html). EJB will then also transparently perform a rollback. – BalusC Jun 10 '15 at 18:49