0

I got a method call from a stateless ejb which looks like the following

@Stateless
@Local(MyCrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class MyCrudServiceBean implements MyCrudService {

    @EJB
    private CrudService crudService;

    @Override
    public void writeLogEntry(StatementLog statementLog) {
        try {
            crudService.execute(statement.getSql());
        } catch (Exception e) {
            crudService.writeLogEntry(statementLog);
            throw new MyApplicationException(e.getLocalizedMessage());
        }
    }

    // ...

}

CrudSerivce:

@Stateless
@Local(CrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
@Interceptors(GenericFrepDataBaseUserInterceptor.class)
public class CrudServiceBean implements CrudService {

    public static final String PERSISTENCE_UNIT_NAME = "name";

    private EntityManager entityManager;

    @PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void execute(String sqlString) {
        Query query = entityManager.createNativeQuery(sqlString);
        query.executeUpdate();
    }

    @Override
    public void writeLogEntry(StatementLog statementLog) {
        entityManager.persist(entity);
    }

    // ....
}

Statement is an entity which got an sql which is invalid (like 'invalid sql'). On execution I get the following error

javax.ejb.EJBTransactionRolledbackException: JBAS011469

If I debug this, I can see that this happens in the line with the logging.

I think the problem is, that because I am getting an exception the transaction gets rolled back. Because of that it is not possible to write into the db, because there is no open session anymore. Is this the case? What's best practice then? To manually open a session by myself seems quite ugly to me.

2
  • Please can you update the question to show how your crudService class accesses the Hibernate session factory? e.g. are you using spring hibernate callbacks, or just calling sessionFactory.getCurrentSession? Commented Oct 27, 2015 at 14:47
  • Thanks for the update. Can you please also update the question to clarify what sort of class your are in when you are calling the crudService? Are you also in a stateless EJB at that point? Commented Oct 27, 2015 at 14:53

1 Answer 1

1

Your method log.writeErrorInDb needs to start its own transaction, so that it can still operate when the main transaction is rolled back. Yes, if your Hibernate session is already closed, then your log class would need to be able to open its own session. However it would probably be better to have a transaction boundary covering this entire block of code, and bind the Hibernate session to that, then set your log method to require a new transaction, to ensure it can operate once the first transaction is marked for rollback. i.e. two transactions, but one session

Based on your code, you should be able to annotate your log method:

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void writeLogEntry(StatementLog statementLog) {
    entityManager.persist(entity);
}
Sign up to request clarification or add additional context in comments.

2 Comments

How con I define a transaction boundary?
Can you provide an example of how to do this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.