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
@EnableMongoRepositories
class EntityDomainConfiguration {
@Bean
EntityDomainService domainService(
EntityARepository entityARepository, EntityBRepository entityBRepository) {
return new EntityDomainService(entityARepository, entityBRepository);
}
}
“Global” Mongo config:
@Configuration
@EnableMongoRepositories()
@EnableTransactionManagement
class ApplicationConfiguration extends AbstractMongoClientConfiguration {
// usual stuff
@Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
Test Mongo container config:
@EnableMongoRepositories
public 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