spring-data-jpa 如何实现多租户Sping Boot 应用程序(其中每个用户都有自己的数据库)

tgabmvqs  于 2022-11-10  发布在  Spring
关注(0)|答案(2)|浏览(394)

我正在构建一个带有Sping Boot 的REST-API,我希望实现一个多租户结构来处理数据。我希望有一个名为Main的数据库,其中包含User表,该表将包含有关用户的数据(用户名、密码...和字段database,该字段将表示哪个数据库被指定给该用户)。每次用户注册时,将创建其相应的数据库(这是我面临的困难之一)。我读过不同的教程,它们都是在application.properties文件中预定义Datasource的。很明显,这不是这里的情况,因为每个用户的数据库将被“动态”创建,或者如果已经创建了数据库则被访问。
工作流程如下所示(尽可能简单地解释):
1.用户注册
1.应用程序创建用户实体并将其保存到Main数据库,然后为用户创建相应的数据库
1.应用程序会检查每次调用的用户是否经过身份验证,如果是,则从其数据库中获取数据
然后有很多关于填充自动创建的数据库的问题。但首先要做的是:)
我的堆栈:POSTGRESQL,Spring Boot
先谢谢你了。

rkue9o1l

rkue9o1l1#

可以通过以下步骤根据需要实现多租户。
1.添加两个配置类,一个用于共享数据库,另一个用于租户数据库,这两个配置类用于配置LocalContainerEntityManagerFactoryBean。此Bean应设置LocalContainerEntityManagerFactoryBean所需的多租户属性,例如

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。例如

@Bean(name = "tenantTransactionManager")
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager tm = new JpaTransactionManager();
    tm.setEntityManagerFactory(this.entityManagerFactory().getObject());
    return tm;
  }

1.实作界面CurrentTenantIdentifierResolver和方法resolveCurrentTenantIdentifier。这应该会根据目前登入的使用者传回承租人的数据库名称。如果没有使用者登入,则传回预设数据库名称
1.用于记住当前租户名称的线程安全上下文保持器
1.使用@Transactional注解注解实体类别的服务实作,并传递适当实体管理员的Bean名称,例如

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

@Transactional("transactionManager") // for shared database.

1.设置新用户注册时的数据库模式创建方法。并将承租人数据库名称作为共享模式中用户表的一列进行维护。
1.如果您使用的是Spring安全性,请实作UserDetailsService界面并实作loadUserByUsername方法,以便传回TenantUser类别的对象,其中包含登入使用者的其他信息(承租人数据库名称)。

public class TenantUser extends org.springframework.security.core.userdetails.User {

  /**The tenand id. */
  private String tenantId;

希望这些步骤能帮助你实现你想要的。有很多文章详细解释了所有这些步骤。我的实现是深嵌入在我的项目,因此它不是在一个状态,可以作为工作示例共享。
很乐意回答任何问题

6g8kf2rb

6g8kf2rb2#

我在这里找到了问题的完整解决方案:
Multi-tenancy: Managing multiple datasources with Spring Data JPA
非常感谢作者@Cepr0。
唯一缺少的是动态地创建DB。当我完成我的实现时,我将在这里更新答案。
更新
我用下面的代码创建了这个数据库,它是由@Milind Barve推荐的。所以谢谢你。

Class.forName("org.postgresql.Driver");
 Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/","postgres", "password");
 Statement smt = con.createStatement();

 smt.executeUpdate("CREATE DATABASE [name_of_db_here] WITH OWNER DEFAULT");

UPDATE:初始化每个新创建的DB的模式,我创建了一个包含所有表创建的.sql文件,并使用FlyWay初始化每个新创建的DB

// INITIALIZE THE DB
            Flyway flyway = Flyway.configure()
                    .dataSource(dataSource)
                    .target(MigrationVersion.LATEST)
                    .load();

            flyway.migrate();

相关问题