Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TransactionRolledbackLocalException Client's transaction aborted when accessing @Singleton

NOTE: Adding this question in short form with an answer after spending far more time than I'd like to admit on finding the cause. Hopefully I'll save someone else some pain.

When delegating a method call to an EJB annotated with @Singleton, the container throws an Exception along the lines of:

TransactionRolledbackLocalException Client's transaction aborted 

The Singleton bean has no data access occurring.

ServiceBeanImpl.java

@Stateless
@Local
public class ServiceBean extends BaseBean{ 
  @EJB private CacheService cacheService;

  public FooObj getFooFromCache(int id) {
    FooObj fooObj = (FooObj) cacheService.get(id);
    if (fooObj == null) {
      fooObj = getEntityById(FooObj.class, id);
      cacheService.put(id, fooObj);  //This throws exception
    }
    return cacheService.get(id);
  }
}

CacheServiceImpl.java

@Singleton
@Startup
public class CacheServiceImpl implements CacheService {
    private Cache cache;

    @PostConstruct
    public void init() {
        CacheManager instance = CacheManager.getInstance();
        cache = instance.getCache("cache");
    }

    @PreDestroy
    public void destroy() {
        CacheManager.getInstance().shutdown();
    }

    public Object get(Object id) {
      return cache.get(id);
    }

    public void put(Object id, Object obj) {
      return cache.put(id, obj);
    }
}

Question Why would calling a Singleton bean that does no data access throw a Transaction exception?

like image 323
Snekse Avatar asked Oct 18 '12 06:10

Snekse


3 Answers

Short answer: check the code stack that executed prior (assuming there are no clues in the StackTrace) for an Exception that is trapped and not propagated (thus no clues in the StackTrace).

In this particular case there was a try/catch around creating a named query. If that named query failed, a secondary query was executed in the catch block. The queries didn't require a transaction, so the fallback query executed properly and returned the expected entities.

However...

That also (I think) marks the transaction as needing a rollback. The @Singleton bean is somewhat of a red-herring. Something about transferring control to that bean made the container check the Transaction, which in turn threw the exception at that point, but the exception was appropriate since the transaction was no longer valid.

Moral of the story:

  • work your way backwards to the last database interaction because that's probably where your problem is.
  • Just because the last database interaction returned data doesn't mean it didn't have an issue (this was the killer for me).
like image 144
Snekse Avatar answered Nov 15 '22 09:11

Snekse


I ran into a similar problem, and found a interesting thing:

From within a @Startup @Singleton I have the following calls

@PostConstruct
public void initHardcodedUsers() {
for (User u : getHardcodedUsers()) {
  if (!userRepository.userExists(u.getName())) {
    userRepository.add(u);
  }
 }
}

UserRepository is a @Stateless EJB with an EntityManager. In the userExists() Method I basically do a "findUserByName" Query with getSingleResult(). If no result is available, a NoResultException is thrown by JPA. I catch that one inside userExists() and return false ("user does not exist").

As NoResultException is a RuntimeException a rollback is forced here, as I just learned!

The most simple approach for that is, to avoid the call to getSingleResult(). Instead of that I use getResultList() and setMaxResults(1). That will simply return an empty List in case of no results, therefore no exception, therefore no rolled back tx.

Good luck :)

Chris

like image 42
skombijohn Avatar answered Nov 15 '22 08:11

skombijohn


A similar problem with TransactionRolledbackLocalException in GlassFish / Payara Server happened to me. But it was caused by a bug in GlassFish / Payara, nothing rolled back the transaction in my application. Restarting the domain fixed it, as described here: javax.ejb.TransactionRolledbackLocalException (Glassfish 3 + JPA + EclipseLink)

like image 41
OndroMih Avatar answered Nov 15 '22 08:11

OndroMih