WriteConflict issue at MongoDB when concurrent hit on the endpoint

I have a Java Spring Boot application and have an endpoint which will POST file and json data, the Java code as below. I would like to do Load Testing on the Java code, so I wrote another application, which will repeatedly call the Java endpoint for 20 times or more.

When call 20 times, the MongoDB will throw error of
Command failed with error 112 (WriteConflict): ‘WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.’

I did some testing, If I remove the mongoTransactionManager() in MongoConfig, it works fine. or if I remove the @JaversSpringDataAuditable in the TestRepo.

I am Spring boot 2.6.4 and the org.mongodb-driver-core and mongodb-driver-sync are 4.4.2

@Configuration
public class MongoConfig{
	@Bean
	public MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory factory){
		return new MongoTransactionManager(factory);
	}
}

@JaversSpringDataAuditable
@Repository
public interface TestRepo extends MongoRepository<TestClass, String>{
}

@Service
public class TestService{
	public MinioRepo minioRepo;
	public TestRepo testRepo; 
	
	@Transactional
	public void addTestClass(TestClass testClass, MultipartFile file){
		minioRepo.putObject(bucket, file.getInputStream); //method to insert/upload file to MinIO
		//after insert into MinIO, there is a listener that can delete the object in MinIO if there is any error/exception in this method. 
		
		testRepo.save(testClass);
	}
}


@Controller
public class TestController{
	public TestService testService;
	
	@PostMapping 
	public void test(@RequestBody String data, MultipartFile file){
		TestClass testClass = ....convert data json into TestClass object...;
		testService.addTestClass(testClass, file);
	}
}

Error message in Spring boot

com.mongodb.MongoCommandException: Command failed with error 112
(WriteConflict): ‘WriteConflict error: this operation conflicted with
another operation. Please retry your operation or multi-document
transaction.’ on server localhost:27017. The full response is
{“errorLabels”: [“TransientTransactionError”], “operationTime”:
{“$timestamp”: {“t”: 1679905729, “i”: 6}}, “ok”: 0.0, “errmsg”:
“WriteConflict error: this operation conflicted with another
operation. Please retry your operation or multi-document
transaction.”, “code”: 112, “codeName”: “WriteConflict”,
“$clusterTime”: {“clusterTime”: {“$timestamp”: {“t”: 1679905730, “i”:
4}}, “signature”: {“hash”: {“$binary”: {“base64”:
“AAAAAAAAAAAAAAAAAAAAAAAAAAA=”, “subType”: “00”}}, “keyId”: 0}}} at
com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:198)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:418)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:342)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:116)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:647)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:71)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:244)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:227)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:127)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:117)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.connection.DefaultServer$OperationCountTrackingConnection.command(DefaultServer.java:348)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.CommandOperationHelper.lambda$executeRetryableWrite$15(CommandOperationHelper.java:411)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$2(OperationHelper.java:564)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:589)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$3(OperationHelper.java:563)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:589)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.OperationHelper.withSourceAndConnection(OperationHelper.java:562)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.CommandOperationHelper.lambda$executeRetryableWrite$16(CommandOperationHelper.java:395)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.async.function.RetryingSyncSupplier.get(RetryingSyncSupplier.java:65)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.CommandOperationHelper.executeRetryableWrite(CommandOperationHelper.java:423)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.TransactionOperation.execute(TransactionOperation.java:70)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.CommitTransactionOperation.execute(CommitTransactionOperation.java:133)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.internal.operation.CommitTransactionOperation.execute(CommitTransactionOperation.java:54)
~[mongodb-driver-core-4.4.2.jar:na] at
com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:212)
~[mongodb-driver-sync-4.4.2.jar:na] at
com.mongodb.client.internal.ClientSessionImpl.commitTransaction(ClientSessionImpl.java:147)
~[mongodb-driver-sync-4.4.2.jar:na] at
org.springframework.data.mongodb.MongoTransactionManager$MongoTransactionObject.commitTransaction(MongoTransactionManager.java:469)
~[spring-data-mongodb-3.3.2.jar:3.3.2] at
org.springframework.data.mongodb.MongoTransactionManager.doCommit(MongoTransactionManager.java:236)
~[spring-data-mongodb-3.3.2.jar:3.3.2] at
org.springframework.data.mongodb.MongoTransactionManager.doCommit(MongoTransactionManager.java:200)
~[spring-data-mongodb-3.3.2.jar:3.3.2] at
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)
~[spring-tx-5.3.16.jar:5.3.16] at
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)
~[spring-tx-5.3.16.jar:5.3.16] at
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)
~[spring-tx-5.3.16.jar:5.3.16] at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)
~[spring-tx-5.3.16.jar:5.3.16] at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
~[spring-tx-5.3.16.jar:5.3.16] at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
~[spring-aop-5.3.16.jar:5.3.16] at
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
~[spring-aop-5.3.16.jar:5.3.16] at
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
~[spring-aop-5.3.16.jar:5.3.16] at
com.example.service.TestService$$EnhancerBySpringCGLIB$$32b03c26.testMultipleCallsToMongoDB()
~[classes/:na] at
com.example.controller.TestController.test(TestController.java:21)
~[classes/:na] at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method) ~[na:na] at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
~[na:na] at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:na] at
java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
~[spring-web-5.3.16.jar:5.3.16] at
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
~[spring-web-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
~[spring-webmvc-5.3.16.jar:5.3.16] at
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
~[spring-webmvc-5.3.16.jar:5.3.16] at
javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
~[tomcat-embed-core-9.0.58.jar:4.0.FR] at
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
~[spring-webmvc-5.3.16.jar:5.3.16] at
javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
~[tomcat-embed-core-9.0.58.jar:4.0.FR] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
~[tomcat-embed-websocket-9.0.58.jar:9.0.58] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
~[spring-web-5.3.16.jar:5.3.16] at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
~[spring-web-5.3.16.jar:5.3.16] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
~[spring-web-5.3.16.jar:5.3.16] at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
~[spring-web-5.3.16.jar:5.3.16] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
~[spring-web-5.3.16.jar:5.3.16] at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
~[spring-web-5.3.16.jar:5.3.16] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:359)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1735)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
~[tomcat-embed-core-9.0.58.jar:9.0.58] at
java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

What does your server do for each of your requests? write conflict can mean like: a transaction A read Obj1 and then tries to write to Obj1, but between this read and write, Obj1 has been modified by another write operation. (based on my understanding of mongo)

related: How WriteConflict errors are managed in Transactions( MongoDB 4.2)