Spring Data Java 25 · Spring Boot 4.1.1

@Transactional with Spring Data MongoDB

Guide to utilise @Transactional with Spring Data MongoDB.

Background

Unlike Spring Data JPA, Spring Data MongoDB does not support @Transactional out of the box. In this guide, we will explore how to implement @Transactional with Spring Data MongoDB.

Scenario

We will implement based on the following scenario:

When a new User is created
Then the status should be ACTIVE

Implementation

Integration Test

We will verify our implementation through integration test whereby we will create a new User and verify that the status is ACTIVE.

@AutoConfigureRestTestClient
@SpringBootTest(webEnvironment = RANDOM_PORT)
@Testcontainers
class CreateUserTests {

    @Container
    @ServiceConnection
    private static final MongoDBContainer mongo = new MongoDBContainer("mongo:latest").withReplicaSet();

    @Autowired
    private RestTestClient restTemplate;

    @Test
    void create() {
        var body = """
                {
                  "username": "rashidi.zin",
                  "name": "Rashidi Zin"
                }
                """;

        restTemplate.post().uri("/users")
                .contentType(APPLICATION_JSON)
                .body(body)
                .exchange()
                .expectStatus().isCreated()
                .expectBody()
                .jsonPath("$.status").isEqualTo("ACTIVE");
    }

}

Event Listener

We will start by implementing an EventListener that will be responsible to assign the status to ACTIVE when a new User is created.

@Component
class UpdateUserStatus {

    @TransactionalEventListener
    public void onBeforeSave(BeforeSaveEvent<User> event) {
        var user = event.getSource();

        user.status(ACTIVE);
    }

}

As we can see, onBeforeSave is annotated with @TransactionalEventListener. This annotation will ensure that the event listener will be executed within a transaction.

Transactional Method

Next, we will implement a transactional method that will create a new User.

@RestController
class UserResource {

    private final UserRepository repository;

    UserResource(UserRepository repository) {
        this.repository = repository;
    }

    @PostMapping("/users")
    @ResponseStatus(CREATED)
    @Transactional
    public User add(@RequestBody User user) {
        return repository.save(user);
    }

}

Configuration Class

Finally, we will configure MongoTransactionManager to enable transaction support for MongoDB.

@Configuration
@EnableTransactionManagement
class MongoTransactionManagerConfiguration {

    @Bean
    public PlatformTransactionManager transactionManager(MongoDatabaseFactory factory) {
        return new MongoTransactionManager(factory);
    }

}

Verification

In order to ensure that our implementation is working as expected, the test implemented in CreateUserTests should pass.