Mikhail Geyer
Mikhail Geyer

Reputation: 1171

WebFlux Spring Boot @Transactional with reactive MongoDB

Does WebFlux Spring Boot @Transactional annotation work with reactive MongoDB?

I use WebFlux Spring Boot with reactive MongoDB like:

    id 'org.springframework.boot' version '2.6.7'
    ...
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
    ...

I marked one of my method @Transactional to test. But it seems the annotation does not work for me. If an error occurs inside this method, then it still adds a row to my mongoDB database.

      import org.springframework.transaction.annotation.Transactional;

      ...

      @Transactional
      public Mono<Chat> createChat(Chat chat) {
        return chatRepository
            .save(chat)
            .map(
                c-> {
                  if (true) {
                    throw new RuntimeException();
                  }
                  return c;
                });
      }

Do I miss something or Spring Boot @Transactional annotation does not work with reactive MongoDB?

I use MongoDB v5.0.8

Upvotes: 3

Views: 3709

Answers (2)

George Sorotos
George Sorotos

Reputation: 11

I used the above configuration for the TransactionManager but then my app was failing with error

Command failed with error 13 (Unauthorized): 'command find requires authentication' on server localhost:27017

It seems that the MongoClient needed username, databaseName and password to work as expected.

@Configuration
@EnableReactiveMongoRepositories
@AllArgsConstructor
public class MongoRepositoryConfiguration extends AbstractReactiveMongoConfiguration {

    private final MongoProperties mongoProperties;

    @Override
    public MongoClient reactiveMongoClient() {
        //Create a mongo client with credentials
        MongoCredential credential = MongoCredential.createCredential(mongoProperties.getUsername(), mongoProperties.getDatabase(), mongoProperties.getPassword());
        return MongoClients.create(
                MongoClientSettings.builder()
                        .credential(credential)
                        .build()
        );
    }

    @Override
    protected String getDatabaseName() {
        return mongoProperties.getDatabase();
    }


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

}

Upvotes: 0

Mikhail Geyer
Mikhail Geyer

Reputation: 1171

It seems like that Spring Data for reactive MongoDB requires to set explicitly a special bean transactionManager. As soon as I have added this bean to my configuration for the reactive MongoDB, the @Transactional annotation started working. So the example method posted in my question does not add a new row to the database anymore if an error occurs inside the method.

Here is my configuration with transactionManager bean:

@Configuration
@EnableReactiveMongoRepositories
@AllArgsConstructor
public class ReactiveMongoConfiguration extends AbstractReactiveMongoConfiguration {

  private final MongoProperties mongoProperties;

  @Override
  public MongoClient reactiveMongoClient() {
    return MongoClients.create();
  }

  @Override
  protected String getDatabaseName() {
    return mongoProperties.getDatabase();
  }

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

P.S. It turns out the defining of transactionManager bean is not enough to enable transactions in reactive MongoDB. The very server of MongoDB should be also configured with replication. I followed these steps and it worked for me.

Upvotes: 5

Related Questions