title: How to prevent Spring from trying to create indexes during MongoDB transactions?
body: <p>I am trying to utilize Spring Data Mongo with Transactions.  I initially ran into an issue where my inserts would fail due to Spring trying to create the collection and/or indexes during the first insert of a document.  I have since solved that issue by creating all of my collections and indexes on startup, prior to any transaction starting.  However, I am still using the Spring Data annotations to define the indexes (ie, <code>@Indexed</code>, <code>@CompoundIndexes</code>, etc.).  However, even though I have created all the indexes already, Spring is still trying to ensure/create the indexes during mongo processing.</p>
  
  <p>In my situation, I am using inheritance with my data types.  Ie., <code>BasicUnit</code> which other Unit's extend.  If I go to store a particular type of Unit, and it is the first time I have tried to save that type of object during the current application run, Spring doesn't recognize it, and creates a new <code>PersistentEntity</code> for it.  As part of creating a new <code>PersistentEntity</code>, Spring posts an event, which <code>MongoPersistentEntityIndexCreator</code> catches, which in turn tries to ensure all indexes are created, and thus an exception is thrown.</p>
  
  <p>Here is the exception:</p>
  
  <pre><code>Caused by: com.mongodb.MongoCommandException: Command failed with error 263 (OperationNotSupportedInTransaction): 'It is illegal to run command createIndexes in a multi-document transaction.' on server 127.0.0.1:27017. The full response is { "operationTime" : { "$timestamp" : { "t" : 1560198052, "i" : 1 } }, "ok" : 0.0, "errmsg" : "It is illegal to run command createIndexes in a multi-document transaction.", "code" : 263, "codeName" : "OperationNotSupportedInTransaction", "$clusterTime" : { "clusterTime" : { "$timestamp" : { "t" : 1560198052, "i" : 1 } }, "signature" : { "hash" : { "$binary" : "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "$type" : "00" }, "keyId" : { "$numberLong" : "0" } } } }
      at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:179)
      at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:293)
      at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:255)
      at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:99)
      at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:444)
      at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:72)
      at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:200)
      at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:269)
      at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:131)
      at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:123)
      at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:242)
      at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:233)
      at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:170)
      at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:163)
      at com.mongodb.operation.CreateIndexesOperation$1.call(CreateIndexesOperation.java:174)
      at com.mongodb.operation.CreateIndexesOperation$1.call(CreateIndexesOperation.java:169)
      at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:453)
      at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:415)
      at com.mongodb.operation.CreateIndexesOperation.execute(CreateIndexesOperation.java:169)
      at com.mongodb.operation.CreateIndexesOperation.execute(CreateIndexesOperation.java:70)
      at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:193)
      at com.mongodb.client.internal.MongoCollectionImpl.executeCreateIndexes(MongoCollectionImpl.java:805)
      at com.mongodb.client.internal.MongoCollectionImpl.createIndexes(MongoCollectionImpl.java:800)
      at com.mongodb.client.internal.MongoCollectionImpl.createIndexes(MongoCollectionImpl.java:793)
      at com.mongodb.client.internal.MongoCollectionImpl.createIndex(MongoCollectionImpl.java:778)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:246)
      at org.springframework.data.mongodb.SessionAwareMethodInterceptor.invoke(SessionAwareMethodInterceptor.java:123)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
      at com.sun.proxy.$Proxy202.createIndex(Unknown Source)
      at org.springframework.data.mongodb.core.DefaultIndexOperations.lambda$ensureIndex$0(DefaultIndexOperations.java:135)
      at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:545)
  </code></pre>
  
  <p>Here is the call stack leanding up to the call to ensureIndex:</p>
  
  <pre><code>DefaultIndexOperations.lambda$ensureIndex$0(IndexDefinition, MongoCollection) line: 135 
  1894975953.doInCollection(MongoCollection) line: not available  
  MongoTemplate.execute(String, CollectionCallback&lt;T&gt;) line: 545  
  DefaultIndexOperations.execute(CollectionCallback&lt;T&gt;) line: 218 
  DefaultIndexOperations.ensureIndex(IndexDefinition) line: 121   
  MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexResolver$IndexDefinitionHolder) line: 145   
  MongoPersistentEntityIndexCreator.checkForAndCreateIndexes(MongoPersistentEntity&lt;?&gt;) line: 135  
  MongoPersistentEntityIndexCreator.checkForIndexes(MongoPersistentEntity&lt;?&gt;) line: 127   
  MongoPersistentEntityIndexCreator.onApplicationEvent(MappingContextEvent&lt;?,?&gt;) line: 111    
  MongoPersistentEntityIndexCreator.onApplicationEvent(ApplicationEvent) line: 54 
  SimpleApplicationEventMulticaster.doInvokeListener(ApplicationListener, ApplicationEvent) line: 172 
  SimpleApplicationEventMulticaster.invokeListener(ApplicationListener&lt;?&gt;, ApplicationEvent) line: 165    
  SimpleApplicationEventMulticaster.multicastEvent(ApplicationEvent, ResolvableType) line: 139    
  AnnotationConfigWebApplicationContext(AbstractApplicationContext).publishEvent(Object, ResolvableType) line: 398    
  AnnotationConfigWebApplicationContext(AbstractApplicationContext).publishEvent(ApplicationEvent) line: 355  
  MongoMappingContext(AbstractMappingContext&lt;E,P&gt;).addPersistentEntity(TypeInformation&lt;?&gt;) line: 405  
  MongoMappingContext(AbstractMappingContext&lt;E,P&gt;).getPersistentEntity(TypeInformation&lt;?&gt;) line: 248  
  MongoMappingContext(AbstractMappingContext&lt;E,P&gt;).getPersistentEntity(Class&lt;?&gt;) line: 191    
  MongoMappingContext(AbstractMappingContext&lt;E,P&gt;).getPersistentEntity(Class) line: 85    
  MongoMappingContext(MappingContext&lt;E,P&gt;).getRequiredPersistentEntity(Class&lt;?&gt;) line: 73 
  EntityOperations$AdaptibleMappedEntity&lt;T&gt;.of(T, MappingContext&lt;MongoPersistentEntity&lt;?&gt;,MongoPersistentProperty&gt;, ConversionService) line: 600  
  EntityOperations$AdaptibleMappedEntity&lt;T&gt;.access$100(Object, MappingContext, ConversionService) line: 580   
  EntityOperations.forEntity(T, ConversionService) line: 105  
  MongoTemplate.doInsert(String, T, MongoWriter&lt;T&gt;) line: 1237
  </code></pre>
  
  <p>You can see where Spring tries to <em>get</em> the persistent entity, then finally decides to <em>add</em>, and then fires off the event, and then the event is handled by attempting to create indexes.</p>
  
  <p>I need to know how to prevent Spring from attempting to create those indexes during a transaction.  </p>
  
  <p>The things I have considered </p>
  
  <ol>
  <li>Try to figure out how to pre-register all my persistent entities,
  but I'm not sure how to do that besides manually keeping a list, or
  writing code to scan the classpath to find all classes that are
  annotated by @Document or extend such a class. </li>
  <li>Completely abandon Spring's index annotations and only use explicit calls to
  ensureIndex for every index I need.</li>
  </ol>
  
  <p>Neither of these solutions is very attractive to me.</p>
  
  <p>I find it hard to believe that no one else has run into similar index issues using Spring Data Mongo with Transactions, so any of you know a solution to this problem, I would love to hear it.</p>
  
  <p>Thanks.</p>