You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot中Liquibase(ddl-auto=none)结合Hibernate-envers无审计数据求助

问题背景

SpringBoot项目中使用Liquibase管理数据库结构,设置spring.jpa.hibernate.ddl-auto=none,手动通过Liquibase执行了包含revinfo、resources_aud等审计表的SQL脚本。引入Hibernate Envers后,对Resource、SupportProgram实体执行增删改操作,审计表中未生成对应数据。

排查与解决步骤

1. 确认实体已开启审计注解

需要确保目标实体类及需审计的关联字段添加了@Audited注解:

@Entity
@Audited // 开启该实体全局审计
public class Resource {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private LocalDateTime createdAt;
    
    @ManyToOne
    @Audited // 关联字段需审计时添加此注解
    private SupportProgram supportProgram;
    
    // getter/setter 省略
}

2. 确保Envers自动配置生效

ddl-auto=none场景下,显式配置Envers核心参数避免监听器未注册:

spring:
  jpa:
    properties:
      hibernate:
        envers:
          autoRegisterListeners: true # 强制开启审计监听器注册
          audit_table_suffix: _aud # 与手动创建的审计表后缀保持一致

3. 修正审计表结构匹配Envers预期

检查revinfo表的主键生成规则,Envers默认需要自增的rev值:

-- 修改原revinfo表的rev字段为自增主键
CREATE TABLE revinfo
(
    rev integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    revtstmp bigint NOT NULL,
    user_id bigint,
    CONSTRAINT fk_revinfo_user_id_users_id FOREIGN KEY (user_id) REFERENCES users(id)
);

其他审计表(如resources_aud)的字段类型、外键关联需与主表及Envers要求匹配,你的现有脚本中字段类型是符合要求的。

4. 确认操作在事务中执行

Envers审计逻辑绑定事务,需保证增删改方法被@Transactional注解修饰:

@Service
public class ResourceService {
    @Autowired
    private ResourceRepository resourceRepository;
    
    @Transactional // 必须在事务内执行,Envers才会生成审计数据
    public Resource saveResource(Resource resource) {
        return resourceRepository.save(resource);
    }
}

5. 检查Liquibase脚本执行顺序

确保创建审计表的脚本在主表(resources、support_programs)创建之后执行,避免外键关联失败导致审计数据无法写入。

6. 开启日志排查细节

添加日志配置,查看Envers是否触发审计SQL:

logging:
  level:
    org.hibernate.SQL: DEBUG
    org.hibernate.envers: DEBUG # 专门打印Envers相关日志

如果日志中无revinfo和xxx_aud表的插入SQL,说明监听器未触发,需回头检查配置。

自定义RevisionEntity注意事项

如果扩展了DefaultRevisionEntity(比如添加user_id字段),需确保自定义监听器正确注册:

@Entity
@RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity extends DefaultRevisionEntity {
    private Long userId;
    
    // getter/setter 省略
}

public class CustomRevisionListener implements RevisionListener {
    @Autowired
    private AuthenticationFacade authenticationFacade;
    
    @Override
    public void newRevision(Object revisionEntity) {
        CustomRevisionEntity customRevision = (CustomRevisionEntity) revisionEntity;
        User currentUser = authenticationFacade.getCurrentUser();
        if (currentUser != null) {
            customRevision.setUserId(currentUser.getId());
        }
    }
}

内容的提问来源于stack exchange,提问作者Kitovraz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 09:00:57