I am failing to get the transactions to work in my basic spring data mongodb app. I've read articles and similar questions here and nothing seems to help. The test is being run with Testcontainers, which appears to launch Mongo with a replica set, meaning transactions should normally work. I am sure that the test config works fine at least with non-transactional code (more in the github link at the end).
The domain service:
public class EntityDomainService { private final EntityARepository repository; private final EntityBRepository entityBRepository; EntityDomainService(EntityARepository repository, EntityBRepository entityBRepository) { this.repository = repository; this.entityBRepository = entityBRepository; } @Transactional public void transactionalAdd(String id1, String id2) { repository.save(EntityA.builder().id(id1).build()); fail(); repository.save(EntityA.builder().id(id2).build()); } private void fail() { throw new RuntimeException(); }}
Module-specific configuration:
@Configuration@EnableMongoRepositoriesclass EntityDomainConfiguration { @Bean EntityDomainService domainService( EntityARepository entityARepository, EntityBRepository entityBRepository) { return new EntityDomainService(entityARepository, entityBRepository); }}
"Global" Mongo config:
@Configuration@EnableMongoRepositories()@EnableTransactionManagementclass ApplicationConfiguration extends AbstractMongoClientConfiguration { // usual stuff @Bean MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) { return new MongoTransactionManager(dbFactory); }}
Test Mongo container config:
@EnableMongoRepositoriespublic class MongoDBContainerTestConfiguration { @Bean @ServiceConnection public MongoDBContainer mongoDBContainer() { return new MongoDBContainer(DockerImageName.parse("mongo:7.0")).withExposedPorts(27017); }}
And finally, the test itself:
@Testcontainers@DataMongoTest@ContextConfiguration(classes = [MongoDBContainerTestConfiguration.class])class EntityADomainSpec extends Specification { @Autowired EntityAMongoRepository simulationRepository @Autowired EntityBMongoRepository plotRepository EntityDomainService service def setup() { service = new EntityDomainConfiguration().domainService(simulationRepository, plotRepository) } def cleanup() { simulationRepository.deleteAll() plotRepository.deleteAll() } def "basic transaction test"() { when: service.transactionalAdd("abc", "def") then: thrown(RuntimeException) !simulationRepository.existsById("abc") }}
Entire minimal reproducible example is hosted on my github (I hope it's pruned to the minimum, but that's my first shot at this). It contains one passing test (to show validity of the config) and the actual test of the transactional behavior:https://github.com/rafalszulejko/mongotransactions
EDIT: removed a lot of code from the github-hosted example