【问题标题】:Log Exception into DB将异常记录到数据库中
【发布时间】:2016-01-26 22:29:44
【问题描述】:

我从一个无状态 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());
        }
    }

    // ...

}

克鲁德服务:

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

    // ....
}

语句是一个实体,它得到一个无效的 sql(如“invalid sql”)。执行时出现以下错误

javax.ejb.EJBTransactionRolledbackException: JBAS011469

如果我对此进行调试,我可以看到这与日志记录一致。

我认为问题在于,因为我遇到了异常,所以事务被回滚。因此,无法写入数据库,因为不再有打开的会话。是这样吗?那么最佳实践是什么?自己手动打开会话对我来说似乎很丑。

【问题讨论】:

  • 请您更新问题以显示您的 crudService 类如何访问 Hibernate 会话工厂?例如你是在使用 spring hibernate 回调,还是只是调用 sessionFactory.getCurrentSession?
  • 感谢您的更新。您能否也更新问题以澄清您在调用 crudService 时属于哪一类?那时您是否也在无状态 EJB 中?

标签: java hibernate exception transactions


【解决方案1】:

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

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

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

【讨论】:

  • 如何定义事务边界?
  • 你能举例说明如何做到这一点吗?
猜你喜欢
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-30
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
相关资源
最近更新 更多