【问题标题】:spring log service and transactionsspring 日志服务和事务
【发布时间】:2012-07-25 08:16:42
【问题描述】:

在我基于 struts2、spring IoC 和 Transasctions、jpa、Hibernate 的应用程序中,我想引入一个“审计日志功能”,它将记录所有重要事件,例如:用户已创建/更新,或有人开了一张票...
我想将此日志保留在数据库中,因此我将拥有一个 DAO。为此,我还创建了一个服务类“AuditLogService”,它将具有事务行为“传播=“REQUIRES_NEW”,因为无论记录的事件是否成功,我都想记录该事件。
问题是,如果我的用户服务中有这样的东西:

@Override
public boolean saveUser(UserDto userDto) {

    User u = new User();        
    u.setFirstName(userDto.getFirstName());
    u.setLastName(userDto.getLastName());
    u.setUserName(userDto.getUserName());       
    u.setPassword(userDto.getPassword());
    u.setIsLdapUser(userDto.getIsLdapUser());
    u.setId(userDto.getId());
    u.setAgentId(userDto.getAgentId());

    Boolean eventStatus = true;
        String event="";
    try{        
        if (u.getId()!=null){           
            dao.update(u);
            event = "UPDATE_USER";
        }else{
            dao.create(u);
            event = "CREATE_USER";          
        }           
    }catch (Exception e) {
        e.printStackTrace();
        eventStatus = false;
        return false;
    }
    finally {
        AuditLogEvent ale = auditLogEventDao.getAuditLogEvent(event);
        auditLogService.addAuditLogEvent(ale, eventStatus,u.toString());
    }

    return false;
}

在提交保存用户方法之前执行审计日志方法并报告事件为真,但实际上该事件为假。
知道我该如何解决这个问题吗?或者这种方法可能不是最好的......?

  • 更新!
    在迈克尔的建议之后,我也将我的服务转变为一个方面

    @Aspect  
    @Service
    class AuditLogAspectImpl implements AuditLogAspect {
        @Autowired
        private AuditLogDao dao;
    
    @Autowired
    private UserDao userDao;
    
    @Override
    @AfterReturning(pointcut = "execution(* xxx.yy.services..*.save*(..))", returning = "retVal")   
    public boolean afterLogEvent(JoinPoint joinPoint,Object retVal){
    }
    

    }

现在我有了像这里这样的方法签名。一切正常,我可以检测操作是否失败或成功,我可以将其记录到日志文件中,但是如果我想通过 dao 类将其记录到数据库中的表中,则当操作失败并且事务滚动时返回我的审核条目未插入。
首先我认为发生这种情况是因为这两个操作,需要审计的实际方法和审计事件都在相同的事务上下文中运行,如果其中一个被回滚,则整个事务是,并且我创建了一个方面日志记录部分的新事务。但这似乎行不通。

知道为什么吗?

【问题讨论】:

    标签: spring spring-transactions


    【解决方案1】:

    该方法不正确,因为声明性事务是通过环绕通知 (AOP) 实现的,因此整个方法都会执行,包括您的 finally 块与审计,然后返回并提交事务。

    我建议您编写自己的审计方面,因为审计或日志记录是横切关注点的主要示例。

    看看Aspect Oriented Programming with Spring

    我会选择After (finally) advice,这样您就可以审核失败和成功的内容。

    实际上并没有那么复杂……您不需要 AspectJ,Spring Aspects 就足以满足给定的目的。

    【讨论】:

    • Spring AOP 是基于默认接口代理的。这意味着,来自外部的呼叫使用代理,这很好。该事务引入了代理以及 AOP。这里没问题。但是 AOP 代理调用原始服务 addAuditLogEvent 并且事务可能没有应用。您需要两者:您的审计方面和单独的服务。将服务自动装配到方面。
    • 太好了,在我听从您的建议并创建了一个新服务之后,该服务使用 REQUIRED_NEW 事务执行,一切都按预期工作
    • @VideanuAdrian 嗨,我遇到了同样的问题。你能详细说明你是如何解决这个问题的吗? create a new service 是什么意思?提前致谢。
    • Quincy,我创建了一个新的服务类(AuditLogServiceImpl 实现 AuditLogService),并使用 @Inject 将其注入到 AuditLogAspectImpl 中。 AuditLogServiceImpl 的 addAuditLogEvent(AuditLogEvent ale) 具有 REQUERES_NEW 事务设置。在我的情况下,这是由 AOP 完成的,如下所示:
    • @VideanuAdrian 我现在明白了。 @Aspect 类和实际的@Transaction 类必须拆分为不同的类。这种编程模式对于像我这样的春季新手来说是一个障碍……谢谢!
    猜你喜欢
    • 2011-08-19
    • 2010-12-30
    • 2021-11-30
    • 1970-01-01
    • 2015-11-27
    • 2021-01-02
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    相关资源
    最近更新 更多