Skip to content

Document how to create MongoTemplate and MongoTransactionManager for default transaction participation #5019

@viktorzavadil

Description

@viktorzavadil

Transaction Rollback Not Working with Spring Data MongoDB 4.3.x and MongoDB Java Driver 5.x

Summary:
When using Spring Data MongoDB 4.3.2 with MongoDB Java Driver 5.0.1 (default via Spring Boot 3.3.2), transaction rollback does not work when using @Transactional and MongoTransactionManager.
However, rollback works as expected when using transactions directly via the raw MongoClient API.

Environment:

  • Spring Boot: 3.3.2
  • Spring Data MongoDB: 4.3.2
  • MongoDB Java Driver: 5.0.1
  • MongoDB server: 5.0.29
  • Java: 21

Configuration:

@Bean
public MongoTemplate mongoTemplate(MongoClient mongoClient, @Value("${spring.data.mongodb.database}") String databaseName) {
    return new MongoTemplate(mongoClient, databaseName);
}

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

Problem Description:

  • When performing write operations (insert/update/delete) inside a method annotated with @Transactional, and an exception is thrown, the transaction manager logs that it is rolling back and calls abortTransaction() on the session.
  • However, the changes are not rolled back in the database – the data remains persisted.
  • When debugging, I found that in the MongoDB Java Driver, the ClientSessionImpl.abortTransaction() method does not actually send an abort command to the server, because the internal flag messageSentInCurrentTransaction is false.
  • This is because Spring Data MongoDB calls MongoCollection.insertOne(document) without passing the session as a parameter, so the driver does not associate the operation with the transaction.

Key findings:

  • When using the raw MongoClient API and passing the session explicitly to all operations, rollback works as expected.
  • With Spring Data MongoDB, the session is not propagated to the driver operations, so the driver does not recognize any transactional operations, and rollback is effectively a no-op.

Specific code location:

  • In MongoTemplate, the method insertDocument (and similar methods for update/delete) calls:
    collection.insertOne(mappedDocument.getDocument());
    instead of the session-aware variant:
    collection.insertOne(session, mappedDocument.getDocument());
  • As a result, the driver does not associate the operation with the current transaction session.

Minimal Example:

@Service
public class TxTestService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Transactional
    public void testTx() {
        mongoTemplate.insert(new MyEntity("test"));
        throw new RuntimeException("rollback!");
    }
}

After calling testTx(), the document is still present in the collection.

Expected behavior:
All changes made within the transaction should be rolled back if an exception occurs.

Actual behavior:
Changes are committed even after rollback is triggered.

Debug details:

  • MongoTransactionManager logs show rollback is initiated and abortTransaction() is called.
  • In the driver, messageSentInCurrentTransaction is false, so no abort command is sent.
  • The root cause is that MongoTemplate does not pass the session to the underlying driver operations.

Steps to reproduce:

  1. Set up Spring Boot project with the above dependencies and configuration.
  2. Create a service method with @Transactional that writes to MongoDB and throws an exception.
  3. Observe that the data is not rolled back.

Workaround:
Using the raw MongoClient API with explicit session management works as expected.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions