Чтобы использовать многодокументные транзакции в MongoDB для нескольких баз данных в Spring Data MongoDB, вам необходимо настроить MongoTemplate
для каждой базы данных, но все они должны использовать один и тот же MongoDbFactory
, потому что он рассматривается как транзакционный ресурс.
Это означает, что вам нужно будет переопределить пару методов MongoTemplate
, чтобы он использовал базу данных, которую он должен использовать (а не тот, который настроен внутри SimpleMongoClientDbFactory
).
Давайте Предположим, что ваши базы данных называются «один» и «два». Затем это выглядит так:
public class MongoTemplateWithFixedDatabase extends MongoTemplate {
private final MongoDbFactory mongoDbFactory;
private final String databaseName;
public MongoTemplateWithFixedDatabase(MongoDbFactory mongoDbFactory,
MappingMongoConverter mappingMongoConverter, String databaseName) {
super(mongoDbFactory, mappingMongoConverter);
this.mongoDbFactory = mongoDbFactory;
this.databaseName = databaseName;
}
@Override
protected MongoDatabase doGetDatabase() {
return MongoDatabaseUtils.getDatabase(databaseName, mongoDbFactory, ON_ACTUAL_TRANSACTION);
}
}
и
@Bean
public MongoDbFactory mongoDbFactory() {
// here, some 'default' database name is configured, the following MongoTemplate instances will ignore it
return new SimpleMongoDbFactory(mongoClient(), getDatabaseName());
}
@Bean
public MongoTransactionManager mongoTransactionManager() {
return new MongoTransactionManager(mongoDbFactory());
}
@Bean
public MongoTemplate mongoTemplateOne(MongoDbFactory mongoDbFactory,
MappingMongoConverter mappingMongoConverter) {
MongoTemplate template = new MongoTemplateWithFixedDatabase(mongoDbFactory,
mappingMongoConverter, "one");
return template;
}
@Bean
public MongoTemplate mongoTemplateTwo(MongoDbFactory mongoDbFactory,
MappingMongoConverter mappingMongoConverter) {
MongoTemplate template = new MongoTemplateWithFixedDatabase(mongoDbFactory,
mappingMongoConverter, "two");
return template;
}
Затем просто введите mongoTemplateOne
и mongoTemplateTwo
в свой сервис, отметьте его метод @Transactional
, и он должен работать .
Реактивный случай
В реактивном случае очень похоже. Конечно, вам нужно использовать реактивные версии классов, такие как ReactiveMongoTemplate
, ReactiveMongoDatabaseFactory
, ReactiveMongoTransactionManager
.
Также есть пара предостережений. Во-первых, вам нужно переопределить 3 метода, а не 2 (поскольку getCollection(String)
также нужно переопределить). Кроме того, мне пришлось сделать это с помощью абстрактного класса, чтобы он работал:
@Bean
public ReactiveMongoOperations reactiveMongoTemplateOne(
@ReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory,
MappingMongoConverter mappingMongoConverter) {
ReactiveMongoTemplate template = new ReactiveMongoTemplate(reactiveMongoDatabaseFactory,
mappingMongoConverter) {
@Override
protected Mono<MongoDatabase> doGetDatabase() {
return ReactiveMongoDatabaseUtils.getDatabase("one", reactiveMongoDatabaseFactory,
ON_ACTUAL_TRANSACTION);
}
@Override
public MongoDatabase getMongoDatabase() {
return reactiveMongoDatabaseFactory.getMongoDatabase(getDatabaseName());
}
@Override
public MongoCollection<Document> getCollection(String collectionName) {
Assert.notNull(collectionName, "Collection name must not be null!");
try {
return reactiveMongoDatabaseFactory.getMongoDatabase(getDatabaseName())
.getCollection(collectionName);
} catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e,
reactiveMongoDatabaseFactory.getExceptionTranslator());
}
}
private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex,
PersistenceExceptionTranslator exceptionTranslator) {
RuntimeException resolved = exceptionTranslator.translateExceptionIfPossible(ex);
return resolved == null ? ex : resolved;
}
};
return template;
}
PS предоставленный код был протестирован с помощью spring-data-mongodb 2.2.4.