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

如何在Quarkus Panache与MongoDB中实现@PrePersist/@PreUpdate?

在MongoDB中自动处理BaseEntity的时间与用户字段

针对你继承ReactivePanacheMongoEntity的BaseEntity,要自动设置createdAt/updatedAt、createdBy/updatedBy,有两种常用方案,对应你在PostgreSQL里用的@PrePersist/@PreUpdate逻辑:

方案一:重写Panache的生命周期回调方法

ReactivePanacheMongoEntity自带预持久化和预更新的回调钩子,直接在BaseEntity里重写即可:

public class BaseEntity extends ReactivePanacheMongoEntity {
    public ZonedDateTime createdAt;
    public ZonedDateTime updatedAt;
    public UUID createdBy;
    public UUID updatedBy;

    // 异步获取当前登录用户ID,替换成你的实际实现
    private Uni<UUID> getCurrentUserId() {
        return SecurityContext.getCurrentUser()
                .map(User::getId) // 假设User实体有getId()返回UUID
                .onFailure().recoverWithNull();
    }

    @Override
    public Uni<Void> prePersist() {
        ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
        createdAt = now;
        updatedAt = now;
        
        return getCurrentUserId()
                .map(userId -> {
                    createdBy = userId;
                    updatedBy = userId;
                    return null;
                })
                .chain(super::prePersist);
    }

    @Override
    public Uni<Void> preUpdate() {
        updatedAt = ZonedDateTime.now(ZoneOffset.UTC);
        
        return getCurrentUserId()
                .map(userId -> {
                    updatedBy = userId;
                    return null;
                })
                .chain(super::preUpdate);
    }
}
  • prePersist:第一次插入实体前触发,初始化创建时间和创建人,同时把更新时间和更新人同步为同一值
  • preUpdate:每次更新实体前触发,更新时间和更新人字段
  • 注意:Reactive环境下获取用户ID必须用异步方式,避免阻塞事件循环

方案二:使用MongoDB实体监听器

如果想把字段填充逻辑和实体解耦,可自定义监听器:

1. 编写监听器类

public class BaseEntityListener {

    // 同样实现异步获取当前用户ID的逻辑
    private Uni<UUID> getCurrentUserId() {
        return SecurityContext.getCurrentUser()
                .map(User::getId)
                .onFailure().recoverWithNull();
    }

    @PreSave
    public Uni<Void> onPreSave(BaseEntity entity) {
        ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
        if (entity.createdAt == null) {
            // 首次插入,初始化创建相关字段
            entity.createdAt = now;
            return getCurrentUserId()
                    .map(userId -> {
                        entity.createdBy = userId;
                        entity.updatedBy = userId;
                        entity.updatedAt = now;
                        return null;
                    });
        } else {
            // 更新操作,只更新时间和更新人
            entity.updatedAt = now;
            return getCurrentUserId()
                    .map(userId -> {
                        entity.updatedBy = userId;
                        return null;
                    });
        }
    }
}

2. 在BaseEntity上绑定监听器

@EntityListeners(BaseEntityListener.class)
public class BaseEntity extends ReactivePanacheMongoEntity {
    public ZonedDateTime createdAt;
    public ZonedDateTime updatedAt;
    public UUID createdBy;
    public UUID updatedBy;
}
  • @PreSave是MongoDB驱动提供的注解,会在每次保存(插入/更新)前触发
  • 监听器逻辑和实体分离,适合多实体共用同一套字段填充规则的场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:17:38