Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何实现多租户Spring引导应用程序(每个用户都有自己的数据库)_Java_Spring_Postgresql_Spring Boot_Spring Data Jpa - Fatal编程技术网

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

Java 如何实现多租户Spring引导应用程序(每个用户都有自己的数据库),java,spring,postgresql,spring-boot,spring-data-jpa,Java,Spring,Postgresql,Spring Boot,Spring Data Jpa,我正在用spring boot构建一个REST-API,我想实现一个多租户结构来处理数据。 我希望有一个名为Main的数据库,其中包含User表,该表将包含有关用户的数据(用户名、密码…和一个Database字段,该字段将指示指定给该用户的数据库)。 每次用户注册其各自的数据库时,都会创建数据库(这是我面临的困难之一)。 我读过不同的教程,它们都在application.properties文件中使用预定义的Datasources。显然,这里的情况并非如此,因为每个用户的数据库都将“动态”创建,

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

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

  • 用户注册
  • 应用程序创建用户实体并将其保存到
    Main
    DB,并为用户创建相应的DB
  • 应用程序会检查用户是否通过了身份验证,如果用户通过了身份验证,则会从其数据库中获取数据
  • 然后,在自动创建DBs时,有很多关于填充DBs的问题。 但首先要做的是:)

    我的堆栈:POSTGRESQL,Spring Boot


    提前感谢您。

    可以按照您的要求通过以下步骤实现多租户

  • 添加两个配置类,一个用于共享数据库,另一个用于租户数据库,用于配置LocalContainerEntityManagerFactoryBean。此bean应该为LocalContainerEntityManagerFactoryBean设置所需的多租户属性 e、 g
  • 实现接口CurrentTenantIdentifier Resolver和方法resolveCurrentTenantIdentifier。这将根据当前登录的用户返回租户的数据库名称。或默认数据库名称(如果没有用户登录)

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

  • 使用@Transactional注释对实体类的服务实现进行注释,并传递相应实体管理器的bean名称,例如

  • 在新用户注册时设置数据库架构创建方法。并将租户数据库名称作为共享架构中用户表中的列之一进行维护

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

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


    很高兴回答更多问题

    我在这里找到了问题的完整解决方案:

    非常感谢作者@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");
    
    更新: 初始化每个新创建的数据库的架构, 我创建了一个包含所有表创建的.sql文件,并使用FlyWay初始化每个新创建的DB

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

    首先,感谢您花时间回复。1) 当我可以为不同的数据源使用application.properties文件时,为什么要使用
    LocalContainerEntityManagerFactoryBean
    ?(因为我在使用boot)(p.s我的方言是Postgres)2)这很清楚,它只是一个检查用户是否登录的类,如果是,那么给我相应的数据库,否则返回一个与主数据库对应的字符串。5) 如何使用Spring boot和Postgresql“动态”创建数据库?没有?createIfExists=true,正如在MySQL中一样,这也显示了很多内容,但我不清楚数据库连接更改时的步骤。如果你能进一步解释,我将非常感激。再次感谢你@为了动态创建数据库,我使用了以下步骤
    Statement stmt=null;stmt=connection.createStatement();stmt.executeUpdate(“创建数据库,如果不存在”+tenantId+“字符集utf8mb4对比utf8mb4\u常规\u ci;”)我正在使用Liquibase进行模式管理。因此,我使用liquibase方法在新创建的数据库中填充模式(表等)。我将尝试共享我的代码,直到您可以参考它,希望它能回答您的问题。我感谢您尝试帮助我,请随时更新我。同时,我将查看上面的链接谢谢:)
    
    @Transactional("tenantTransactionManager") // for tenant database
    
    @Transactional("transactionManager") // for shared database.
    
    
    public class TenantUser extends org.springframework.security.core.userdetails.User {
     
    
      /** The tenand id. */
      private String tenantId;
    
     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");
    
    // INITIALIZE THE DB
                Flyway flyway = Flyway.configure()
                        .dataSource(dataSource)
                        .target(MigrationVersion.LATEST)
                        .load();
    
                flyway.migrate();