Chris311
Chris311

Reputation: 3992

Log Exception into DB

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.

Upvotes: 0

Views: 780

Answers (1)

Hedley
Hedley

Reputation: 1092

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);
}

Upvotes: 1

Related Questions