【问题标题】:Making spring-data-mongodb multi-tenant制作 spring-data-mongodb 多租户
【发布时间】:2013-05-01 20:06:08
【问题描述】:

在去年8月postsbzoom提出了一个解决方案,使spring-data-mongoDB多租户:

“您必须创建自己的 RepositoryFactoryBean。这是来自 Spring Data MongoDB Reference Docs 的示例。您仍然需要实现自己的 MongoTemplate 并延迟或删除 ensureIndexes() 调用。但是您必须重写一些类确保调用您的 MongoTemplate 而不是 Spring 的。”

有人实现了这个或类似的东西吗?

【问题讨论】:

    标签: java spring mongodb spring-data spring-data-mongodb


    【解决方案1】:

    这里有很多剥猫皮的方法。这基本上都归结为您希望在哪个级别应用租约。

    基础知识

    基本方法是在每个线程的基础上绑定某种标识客户的密钥,以便您可以了解当前执行线程处理的客户。这通常通过使用一些与身份验证相关的信息填充ThreadLocal 来实现,因为您通常可以从登录用户中获取租户。

    现在,如果这已经到位,那么就可以选择在哪里应用租户知识。让我简要概述一下最常见的:

    数据库级别的多租户

    为多个客户端分离数据的一种方法是为每个租户设置单独的数据库。 Spring Data MongoDB 对此的核心抽象是MongoDBFactory 接口。这里最简单的方法是覆盖 SimpleMongoDbFactory.getDb(String name) 并使用数据库名称调用父方法,例如由租户前缀等丰富。

    集合级别的多租户

    另一种选择是拥有特定于租户的集合,例如通过租户前缀或后缀。这种机制实际上可以通过在 @Document 注释的 collectionName 属性中使用 Spring 表达式语言 (SpEl) 来利用。首先,通过 Spring bean 暴露租户前缀:

     @Component("tenantProvider")
     public class TenantProvider {
    
       public String getTenantId() {
         // … implement ThreadLocal lookup here
       }
     }
    

    然后在你的域类型@Document映射中使用SpEL:

     @Document(collectionName = "#{tenantProvider.getTenantId()}_accounts"
     public class Account { … }
    

    SpEl 允许您按名称引用 Spring bean 并在它们上执行方法。 MongoTemplate(因此存储库抽象可传递)将使用文档类的映射元数据,映射子系统将评估 collectionName 属性以找出要与之交互的集合。

    【讨论】:

    • 非常感谢 Oliver 的及时回复。我们已经决定采用第一种方法,即数据库级别。 sbzoom 对此提出了担忧:“MongoTemplate 在其构造函数中运行其 ensureIndexes() 方法。此方法调用数据库以确保数据库中存在带注释的索引。当 Spring 启动时调用 MongoTemplate 的构造函数,因此我什至没有机会设置 ThreadLocal 变量”。解决这个问题的方法是什么?
    • @Oliver 对于集合级别的多租户,是否存在在集合启动时不会创建 Mongo 索引的问题?它会按需执行吗?
    • 但是如何使用MongoRepositories,他们在创建时需要MongoTemplate。为了我的目的,我希望有一些像 <Tenant, Repository> 这样的映射,但是如何实现呢?
    • Spring Boot 1.3.3 + Spring Data MongoDB 1.8.2 用户在这里,面临同样的索引问题。在stackoverflow.com/questions/37459810/… 上打开了一个新问题
    • mongo mutitenancy in general: web.archive.org/web/20140812091703/http://support.mongohq.com/… ,所以我会在每个文档中为所有客户 + customer_id 使用一个数据库
    【解决方案2】:

    我对 Oliver Gierke 有类似的做法。 至少在数据库级别。 https://github.com/Loki-Afro/multi-tenant-spring-mongodb 您应该能够执行以下操作:

            MultiTenantMongoDbFactory.setDatabaseNameForCurrentThread("test");
            this.personRepository.save(createPerson("Phillip", "Wirth", ChronoUnit.YEARS.between(
                    LocalDate.of(1992, Month.FEBRUARY, 3),
                    LocalDate.now())));
    
            System.out.println("data from test: " + this.personRepository.findAll());
    //        okay? fine. - lets switch the database
            MultiTenantMongoDbFactory.setDatabaseNameForCurrentThread("test666");
    
    //        should be empty
            System.out.println("data from test666: " + this.personRepository.findAll());
    

    【讨论】:

      【解决方案3】:

      对于springboot 2.3.3

      覆盖 doGetMongoDatabase 有助于实现多租户

      protected MongoDatabase doGetMongoDatabase(String dbName) {   
      }
      

      https://github.com/jose-m-thomas/mongo_multi_tenancy_spring_boot_2_3_3

      【讨论】:

        【解决方案4】:

        使用 Spring Boot + MongoDB + Spring MVC 和共享/全局数据库配置的全功能多租户/租户。

        https://github.com/arun2pratap/multitenant-spring-mongodb

        【讨论】:

          猜你喜欢
          • 2016-09-24
          • 2015-01-10
          • 1970-01-01
          • 1970-01-01
          • 2022-11-18
          • 2017-03-05
          • 2014-04-19
          • 2019-01-03
          相关资源
          最近更新 更多