멀티 테넌트 Spring Boot 애플리케이션을 구현하는 방법 (각 사용자는 자체 데이터베이스를 가짐)

Nov 21 2020

스프링 부트로 REST-API를 구축 중이며 데이터를 처리하기 위해 다중 테넌트 구조를 구현하고 싶습니다. 사용자에 대한 데이터 (사용자 이름, 암호 ... 및 이 사용자에게 지정된 데이터베이스를 나타내는 필드) 를 포함하는 테이블 Main이있는 데이터베이스 하나를 갖고 싶습니다 . 사용자가 가입 할 때마다 자신의 DB가 생성됩니다 (이것이 제가 어려움을 겪고있는 부분 중 하나입니다). 나는 다른 튜토리얼을 읽었으며 모두 파일에 사전 정의 된 s가 있습니다. 각 사용자에 대한 DB는 "즉시"생성되거나 이미 생성 된 경우 액세스되므로 여기서는 분명히 그렇지 않습니다.UserdatabaseDatasourceapplication.properties

워크 플로는 다음과 같습니다 (가능한 간단하게 설명 됨).

  1. 사용자 가입
  2. 앱은 User Entity를 생성하고이를 MainDB에 저장 하고 사용자를위한 각 DB를 생성합니다.
  3. 앱은 사용자가 인증 된 경우 각 호출을 확인하고 인증 된 경우 해당 DB에서 데이터를 가져옵니다.

그러면 자동으로 생성 될 때 DB를 채우는 것과 관련하여 많은 질문이 있습니다. 하지만 먼저 먼저 :)

내 스택 : POSTGRESQL, Spring Boot

미리 감사드립니다.

답변

3 MilindBarve Nov 21 2020 at 18:16

다음 단계에 따라 필요에 따라 다중 테넌시를 수행 할 수 있습니다.

  1. LocalContainerEntityManagerFactoryBean을 구성하는 공유 데이터베이스와 테넌트 데이터베이스에 대한 구성 클래스 2 개를 추가합니다. 이 빈은 예를 들어 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 메서드를 구현합니다. 현재 로그인 한 사용자를 기반으로 테넌트의 데이터베이스 이름을 반환해야합니다. 로그인 한 사용자가없는 경우 기본 데이터베이스 이름

  2. 현재 테넌트 이름을 기억하는 스레드 안전 컨텍스트 홀더

  3. @Transactional 주석으로 엔티티 클래스에 대한 서비스 구현에 주석을 달고 적절한 엔티티 관리자의 빈 이름을 전달하십시오.

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

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

  1. 신규 사용자 등록시 데이터베이스 스키마 생성 방법을 설정합니다. 공유 스키마의 사용자 테이블에있는 열 중 하나로 테넌트 데이터베이스 이름을 유지합니다.

  2. 스프링 보안을 사용하는 경우 UserDetailsService 인터페이스를 구현하고 사용자 로그인에 대한 추가 정보 (테넌트 데이터베이스 이름)가 포함 된 TenantUser 클래스의 개체를 반환하도록 loadUserByUsername 메서드를 구현합니다.

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

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

이 단계가 원하는 것을 달성하는 데 도움이되기를 바랍니다. 이 모든 단계를 자세히 설명하는 많은 문서가 있습니다. 내 구현은 내 프로젝트에 깊이 포함되어 있으므로 작업 예제로 공유 할 수있는 상태가 아닙니다.

추가 질문에 기꺼이 답변

Renis1235 Nov 23 2020 at 13:43

여기에서 내 문제에 대한 완전한 해결책을 찾았습니다.

멀티 테넌시 : SpringData 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");

업데이트 : 새로 생성 된 각 DB의 스키마를 초기화하고, 모든 테이블 생성이 포함 된 .sql 파일을 생성하고 FlyWay를 사용하여 새로 생성 된 각 DB를 초기화합니다.

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

            flyway.migrate();