Collection based multi tenancy in spring data mong

2020-07-30 03:54发布

问题:

I am starting a MULTI-TENANT project in spring data mongodb. After reading this post, collection per tenant is a pretty decent approach in mongodb.

So how can I achieve this in Spring Data Mongo? Apparently, There's no out-of-box solution provided, but I thought I could tweak MongoTemplate by overriding determineCollectionName method but I assume its not a public nor protected method for purpose.

However, I set up database per tenant approach very easily by extending SimpleMongoDbFactory and using LocalThread variable by following the tips provided here.

So, the questions are:

  1. Is there any safe way I can override the collection and domain class name mappings? p.s: This should happen at runtime, so I think @collection annotation won't help at all.
  2. If the collection per tenant is impossible, how much performance and resource penalties will I get for taking multi db approach?

回答1:

You could extend MappingMongoEntityInformation to override getCollectionName(). The repository operations call getCollectionName() on each operation. I'm assuming the tenantId would be a ThreadLocal

public class TenantThreadLocal extends ThreadLocal<String> {
    private final static TenantThreadLocal instance = new TenantThreadLocal();

    public static TenantThreadLocal instance() {
        return instance;
    }
}

And the overridden class with the constructors omitted.

public class TenantMappingMongoEntityInformation<T, ID extends java.io.Serializable>  extends MappingMongoEntityInformation<T, ID> {

    @Override
    public String getCollectionName() {
        return TenantThreadLocal.instance().get() + super.getCollectionName();
    }
}

Then create your repository:

MongoPersistentEntity<YourObject> persistentEntity = 
    (MongoPersistentEntity<YourObject>) 
    mongoOperations.getConverter()
    .getMappingContext()
    .getPersistentEntity(YourObject.class);

MongoEntityInformation<YourObject, ObjectId> mongoEntityInformation =
    new MappingMongoEntityInformation<YourObject, ObjectId>(persistentEntity);

CrudRepository<YourObject, ObjectId> repository =
    new SimpleMongoRepository<YourObject, ObjectId>(mongoEntityInformation, mongoOperations);