有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何实现多租户Spring Boot应用程序(每个用户都有自己的数据库)

我正在用spring boot构建一个REST-API,我想实现一个多租户结构来处理数据。 我希望有一个名为Main的数据库,它将有User表,它将有一个关于用户的数据(用户名、密码……和一个database字段,该字段将指示指定给该用户的数据库)。 每次用户注册各自的数据库时都会被创建(这是我面临的困难之一)。 我读过不同的教程,它们都是在application.properties文件中预定义的Datasource。显然,这里的情况并非如此,因为每个用户的数据库都将“动态”创建,如果已经创建了数据库,则可以访问

工作流程如下(尽可能简单地解释):

  1. 用户注册
  2. 应用程序创建用户实体并将其保存到MainDB,并为用户创建相应的DB
  3. 应用程序会检查用户是否通过了身份验证,如果用户通过了身份验证,则从其数据库中获取数据

然后,在自动创建DBs时,有很多关于填充DBs的问题。 但首要的事情是:)

我的堆栈:POSTGRESQL、Spring Boot

提前谢谢你


共 (1) 个答案

  1. # 1 楼答案

    通过以下步骤,可以根据需要实现多租户

    1. 添加两个配置类,一个用于共享数据库,另一个用于租户数据库,用于配置LocalContainerEntityManagerFactoryBean。这个bean应该为LocalContainerEntityManagerFactoryBean设置所需的多租户属性 e、 g
     Map<String, Object> properties = hibernateProperties.determineHibernateProperties(
            this.properties.getProperties(), new HibernateSettings());
    
    
        properties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
        properties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, this.connectionProvider);
        properties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, this.resolver);
        properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");
    

    该类还应该为每种类型实现命名bean transactionManager。e、 g

     @Bean(name = "tenantTransactionManager")
      public PlatformTransactionManager transactionManager() {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(this.entityManagerFactory().getObject());
        return tm;
      }
    
    
    1. 实现接口CurrentTenantIdentifier Resolver和方法resolveCurrentTenantIdentifier。这将根据当前登录的用户返回租户的数据库名称。或默认数据库名称(如果没有用户登录)

    2. 线程安全上下文持有者,用于记住当前租户名称

    3. 用@Transactional annotation注释实体类的服务实现,并传递相应实体管理器的bean名称,例如

    @Transactional("tenantTransactionManager") // for tenant database
    

    @Transactional("transactionManager") // for shared database.
    
    
    1. 在新用户注册时设置数据库架构创建方法。并将租户数据库名称作为共享模式中用户表中的列之一进行维护

    2. 如果您使用的是spring安全性,请实现UserDetailsService接口并实现方法loadUserByUsername,以便它返回一个TenantUser类的对象,该对象包含用户登录的其他信息(租户数据库名称)

    public class TenantUser extends org.springframework.security.core.userdetails.User {
     
    
      /** The tenand id. */
      private String tenantId;
    

    希望这些步骤能帮助你实现你想要的。有许多文章详细解释了所有这些步骤。我的实现深深嵌入到我的项目中,因此它不处于可以作为工作示例共享的状态

    很高兴回答任何进一步的问题