Текущий проект spring-data-mongodb использует изменяемые объекты для загрузки состояния из базы данных даже в реактивном приложении.Это считается плохой практикой, и я могу найти некоторые проблемы даже в самом проекте spring-data-mongodb.Например, фрагмент кода из ReactiveMongoTemplate:
protected <T> Mono<T> doSave(String collectionName, T objectToSave, MongoWriter<Object> writer) {
assertUpdateableIdIfNotSet(objectToSave);
return createMono(collectionName, collection -> {
T toSave = maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName)).getSource();
AdaptibleEntity<T> entity = operations.forEntity(toSave, mongoConverter.getConversionService());
Document dbDoc = entity.toMappedDocument(writer).getDocument();
maybeEmitEvent(new BeforeSaveEvent<T>(toSave, dbDoc, collectionName));
return saveDocument(collectionName, dbDoc, toSave.getClass()).map(id -> {
T saved = entity.populateIdIfNecessary(id);
return maybeEmitEvent(new AfterSaveEvent<>(saved, dbDoc, collectionName)).getSource();
});
});
}
Как вы можете видеть, entity.populateIdIfNeeded (id) является мутирующим объектом-сущностью в другом потоке, что считается ошибкой в многопоточном приложении, если только вы не используете entity, где все сеттерысинхронизированы.
Какова правильная и рекомендуемая практика для решения проблем параллелизма с использованием изменяемых объектов с реактивным интерфейсом mongodb?Рассмотрим следующий пример:
reactiveMongoOperations.findById("id2", Customer.class) // calls Customer setters on thread1
.zipWith(reactiveMongoOperations.findById("id2", Account.class)) // calls Account setters on thread2
.map(t -> perform(t.getT1(), t.getT2())); // access objects on thread2
Чтобы сделать этот код безопасным, вам нужно иметь неизменяемые классы Customer и Account (которые поддерживает пружина data mongodb) или все сеттеры должны быть синхронизированы / volatile делает ваш код оченьс поддержкой потоков и ошибок.