使用Spring Data MongoDB实现基于集合的多租户功能

5
我们的Spring Boot 1.3.3应用程序使用Spring Data MongoDB 1.8.4将数据持久化到MongoDB(2.6或3.2)。我们需要支持多租户。我们选择使用“基于集合”的租户模式,即每个租户都有自己的一组集合。例如,对于Article实体,集合为“{tenantName}_articles”。Oliver Gierke在Making spring-data-mongodb multi-tenant中友好地解释了一个实现方法,例如:
@Document(collectionName = "#{tenantProvider.getTenantId()}_articles")

这在理论上看起来非常好,但实际应用中存在两个问题,其中一个问题非常严重:
问题1(我可以忍受):在应用程序启动时,Spring Boot使数据库为具有自定义索引的实体(如@Indexed属性)构建索引。但是在启动时,没有“当前租户”,因此Spring Data会创建不相关的集合,例如“_articles”。我们该如何防止这种情况发生?
问题2(主要问题):在运行时,多租户集合(例如“{tenantName}_articles”)被创建并使用,但没有使用自定义索引(除了"_id"上的默认MongoDB索引)。我怀疑Spring在运行时忽略了索引,因为它认为它已经在启动时完成了工作。这是一个很大的性能问题。我们该如何解决这个问题?
谢谢您的时间。
1个回答

9
发现了一种重新创建指定租户索引的方法:
String tenantName = ...;

MongoMappingContext mappingContext = (MongoMappingContext) mongoTemplate.getConverter().getMappingContext();
MongoPersistentEntityIndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);

for (BasicMongoPersistentEntity entity : mappingContext.getPersistentEntities()) {
    if (entity.findAnnotation(Document.class) == null) {
        // Keep only collection roots
        continue;
    }

    String collectionName = entity.getCollection();
    if (!collectionName.startsWith(tenantName)) {
        // Keep only dynamic entities
        continue;
    }

    IndexOperations indexOperations = mongoTemplate.indexOps(collectionName);
    for (MongoPersistentEntityIndexResolver.IndexDefinitionHolder holder : resolver.resolveIndexForEntity(entity)) {
        indexOperations.ensureIndex(holder.getIndexDefinition());
    }
}

花了我一些时间才弄明白这个问题。希望这可以帮到你。欢迎提出改进意见。

1
在哪里编写这段代码?或者给出编写此代码的位置。 - Kamlesh
如果您的租户可以注册,那么这段代码可以在注册过程中使用。 - Stephane L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接