Как предотвратить попытки Spring создать индексы во время транзакций MongoDB? - PullRequest
2 голосов
/ 10 июня 2019

Я пытаюсь использовать Spring Data Mongo с транзакциями. Сначала я столкнулся с проблемой, из-за которой мои вставки не работали из-за того, что Spring пытался создать коллекцию и / или индексы во время первой вставки документа. С тех пор я решил эту проблему, создав все свои коллекции и индексы при запуске до начала какой-либо транзакции. Однако я все еще использую аннотации Spring Data для определения индексов (т. Е. @Indexed, @CompoundIndexes и т. Д.). Однако, хотя я уже создал все индексы, Spring все еще пытается обеспечить / создать индексы во время обработки монго.

В моей ситуации я использую наследование с моими типами данных. Т.е., BasicUnit какой другой блок распространяется. Если я иду, чтобы сохранить определенный тип модуля, и я впервые пытаюсь сохранить этот тип объекта во время текущего запуска приложения, Spring не распознает его и создает для него новый PersistentEntity. В рамках создания нового PersistentEntity Spring отправляет событие, которое MongoPersistentEntityIndexCreator перехватывает, которое, в свою очередь, пытается обеспечить создание всех индексов, и, таким образом, генерируется исключение.

Вот исключение:

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)

Вот стек вызовов, привязанный к вызову для обеспечения индексирования:

DefaultIndexOperations.lambda$ensureIndex$0(IndexDefinition, MongoCollection) line: 135 
1894975953.doInCollection(MongoCollection) line: not available  
MongoTemplate.execute(String, CollectionCallback<T>) line: 545  
DefaultIndexOperations.execute(CollectionCallback<T>) line: 218 
DefaultIndexOperations.ensureIndex(IndexDefinition) line: 121   
MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexResolver$IndexDefinitionHolder) line: 145   
MongoPersistentEntityIndexCreator.checkForAndCreateIndexes(MongoPersistentEntity<?>) line: 135  
MongoPersistentEntityIndexCreator.checkForIndexes(MongoPersistentEntity<?>) line: 127   
MongoPersistentEntityIndexCreator.onApplicationEvent(MappingContextEvent<?,?>) line: 111    
MongoPersistentEntityIndexCreator.onApplicationEvent(ApplicationEvent) line: 54 
SimpleApplicationEventMulticaster.doInvokeListener(ApplicationListener, ApplicationEvent) line: 172 
SimpleApplicationEventMulticaster.invokeListener(ApplicationListener<?>, ApplicationEvent) line: 165    
SimpleApplicationEventMulticaster.multicastEvent(ApplicationEvent, ResolvableType) line: 139    
AnnotationConfigWebApplicationContext(AbstractApplicationContext).publishEvent(Object, ResolvableType) line: 398    
AnnotationConfigWebApplicationContext(AbstractApplicationContext).publishEvent(ApplicationEvent) line: 355  
MongoMappingContext(AbstractMappingContext<E,P>).addPersistentEntity(TypeInformation<?>) line: 405  
MongoMappingContext(AbstractMappingContext<E,P>).getPersistentEntity(TypeInformation<?>) line: 248  
MongoMappingContext(AbstractMappingContext<E,P>).getPersistentEntity(Class<?>) line: 191    
MongoMappingContext(AbstractMappingContext<E,P>).getPersistentEntity(Class) line: 85    
MongoMappingContext(MappingContext<E,P>).getRequiredPersistentEntity(Class<?>) line: 73 
EntityOperations$AdaptibleMappedEntity<T>.of(T, MappingContext<MongoPersistentEntity<?>,MongoPersistentProperty>, ConversionService) line: 600  
EntityOperations$AdaptibleMappedEntity<T>.access$100(Object, MappingContext, ConversionService) line: 580   
EntityOperations.forEntity(T, ConversionService) line: 105  
MongoTemplate.doInsert(String, T, MongoWriter<T>) line: 1237

Вы можете увидеть, где Spring пытается получить постоянную сущность, затем, наконец, решает добавить , а затем инициирует событие, а затем событие обрабатывается путем попытки создания индексы.

Мне нужно знать, как предотвратить попытки Spring создать эти индексы во время транзакции.

Вещи, которые я рассмотрел

  1. Попробуй выяснить, как предварительно зарегистрировать все мои постоянные сущности, но я не уверен, как это сделать, кроме ручного ведения списка, или написание кода для сканирования пути к классам, чтобы найти все классы, которые аннотируется @Document или расширяет такой класс.
  2. Полностью отказаться от индексных аннотаций Spring и использовать только явные вызовы sureIndex для каждого нужного мне индекса.

Ни одно из этих решений не очень привлекательно для меня.

Мне трудно поверить, что никто другой не сталкивался с подобными проблемами индексации, используя Spring Data Mongo с транзакциями, поэтому любой из вас знает решение этой проблемы, я хотел бы услышать это.

Спасибо.

1 Ответ

1 голос
/ 11 июня 2019

Оказывается, это было вызвано моим расположением пакета java. Похоже, что Spring MongoDB будет сканировать и регистрировать все объекты @Document и @Persistent в том же пакете, что и MongoConfiguration по умолчанию. Однако у меня этот класс в другом пакете, чем у всех моих сущностей.

Я перебил MongoConfigurationSupport#getMappingBasePackages в моем MongoConfiguration, а затем Spring смог найти и «предварительно зарегистрировать» все мои сущности, поэтому они больше не «обнаруживаются» в середине транзакции.

public class MongoConfiguration extends AbstractMongoConfiguration {

....

    /* (non-Javadoc)
     * @see org.springframework.data.mongodb.config.MongoConfigurationSupport#getMappingBasePackages()
     */
    @Override
    protected Collection<String> getMappingBasePackages() {
        java.util.List<String> packages = new ArrayList<>(1);
        packages.add("my.entity.base.package");
        return packages;
    }
}
...