实现 AbstractMongoEventListener 时事务不工作

Transactional not working while implementing AbstractMongoEventListener

提问人:zellcorp 提问时间:10/15/2023 最后编辑:zellcorp 更新时间:10/16/2023 访问量:62

问:

我尝试保存包含子文档列表的父文档。 在保存父项时,我检查是否需要根据注释保存嵌套的子项。 如果是,我将子文档保存在父文档之前,如果无法保存父文档,我想取消操作。

为了测试它,我在保存子文档后立即抛出异常,并检查文档是否已保存。

这是我使用的代码,这是我对 AbstractMongoEventListener.onBeforeConvert() 的实现:

@Component
public class CascadeSaveMongoListener extends AbstractMongoEventListener<Object> {

    private final ReactiveMongoTemplate reactiveMongoTemplate;

    public CascadeSaveMongoListener(ReactiveMongoTemplate reactiveMongoTemplate) {
        this.reactiveMongoTemplate = reactiveMongoTemplate;
    }

    @Override
    public void onBeforeConvert(BeforeConvertEvent<Object> event) {
        ReflectionUtils.doWithFields(event.getSource().getClass(), new CascadeSaveCallback(event, reactiveMongoTemplate));
    }

}

和这个回调:

public class CascadeSaveCallback implements ReflectionUtils.FieldCallback {

    private MongoMappingEvent event;
    private ReactiveMongoTemplate reactiveMongoTemplate;

    CascadeSaveCallback(MongoMappingEvent event, ReactiveMongoTemplate reactiveMongoTemplate) {
        this.event = event;
        this.reactiveMongoTemplate = reactiveMongoTemplate;
    }

    @Override
    public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
        ReflectionUtils.makeAccessible(field);
        if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)) {
            final Object fieldValue = field.get(event.getSource());
            if (Collection.class.isAssignableFrom(fieldValue.getClass())) {
                Mono<Collection<Object>> mono = Mono.just((Collection<Object>) fieldValue);
                reactiveMongoTemplate.insertAll(mono).then().subscribe();
                throw new IllegalArgumentException("Not yet implemented");
            } else {
                reactiveMongoTemplate.insert(fieldValue);
            }
        }
    }
}

为了给您提供更多信息, 我从官方映像中使用带有 docker 的 mongo,这里是我用来使用 replica 运行它并启用事务的命令:

$ docker run --name my-mongo -p 27017:27017 -d mongo --replSet rs0 && sleep 2 && docker exec my-mongo mongosh --eval "rs.initiate();"

这里是 SpringBootApplication 类、服务、Entity 和我的 mongoReactiveConfig 类:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableTransactionManagement
@EnableMongoRepositories
public class ApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }

}
@Service
public class ApiService {

    private final ParentRepository parentRepository;

    public ApiService(ParentRepository parentRepository) {
        this.parentRepository = parentRepository;
    }
    
    @Transactional
    public Mono<Parent> save(Parent parent) {
        return parentRepository.save(parent);
    }
}
@Document
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Parent extends BaseEntity {
    @JsonFormat(pattern = "dd-MM-yyyy HH:mm:ss")
    private LocalDateTime startDate;

    @DBRef
    @CascadeSave
    List<Child> children;
}
@Configuration
public class MongoReactiveConfig extends AbstractReactiveMongoConfiguration {

    @Bean
    ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory factory) {
        return new ReactiveMongoTransactionManager(factory);
    }

    @Override
    public MongoClient reactiveMongoClient() {
        return MongoClients.create("mongodb://localhost:27017/api");
    }

    @Override
    protected String getDatabaseName() {
        return "api";
    }
}

首先,我尝试不注入 ReactiveMongoTemplate。但交易没有成功。 然后我尝试了它,我得到了相同的结果。

当我运行代码时,我可以看到异常,但我仍然在mongoDB中看到Child文档,我希望它不在这里。

有人有想法吗? PS:英语不是我的母语,我为我犯的任何错误道歉。

编辑: 从我得到的日志来看,它似乎与调用 ApiService.save() 的线程与用于自定义侦听器的线程之间的绑定有关。 创建一个新事务,然后自定义侦听器抛出异常并开始回滚。 但是然后我可以看到插入指令的开始。

java spring-data-jpa spring-webflux spring-transactions spring-data-mongodb-反应

评论


答: 暂无答案