将异常记录到DB中

时间:2015-10-27 13:24:41

标签: java hibernate exception transactions

我从无状态ejb接到一个方法调用,看起来像下面的

@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是一个获得sql无效的实体(如'invalid sql')。执行时我收到以下错误

javax.ejb.EJBTransactionRolledbackException:JBAS011469

如果我调试这个,我可以看到这发生在记录的行中。

我认为问题是,因为我得到一个例外,事务被回滚。因此,无法写入数据库,因为不再有打开的会话。是这样的吗?那么最佳做法是什么?单独手动打开会话对我来说似乎很难看。

1 个答案:

答案 0 :(得分:1)

您的方法log.writeErrorInDb需要启动自己的事务,以便在回滚主事务时它仍然可以运行。是的,如果您的Hibernate会话已经关闭,那么您的日志类需要能够打开自己的会话。但是,最好让事务边界覆盖整个代码块,并将Hibernate会话绑定到该代码,然后将日志方法设置为需要新事务,以确保在第一个事务标记为回滚后它可以运行。即两次交易,但一次会议

根据您的代码,您应该能够注释您的日志方法:

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