리서치

[Springboot] 멀티 데이터소스 (MyBatis, JPA)

꾸준함. 2023. 3. 25. 11:55

개요

최근 회사 업무를 하며 멀티 테넌시 아키텍처를 적용한 서비스를 개발했습니다.
요구사항은 아래와 같았습니다.

  • 사용자 로그인 정보를 토대로 해당 tenant에 매핑된 데이터베이스와 연동
  • 런타임에 테넌트 추가 가능
    • 즉, 재기동 없이 동적으로 사용자와 사용자가 매핑된 데이터소스를 추가 가능
  • 테넌트를 추가할 때 데이터베이스 및 테이블 자동 생성

 
클라우드 시장이 성장함에 따라 멀티 테넌시를 지원하는 XaaS가 늘어날 것으로 판단되기 때문에 해당 내용을 다루고 싶었고 생각보다 코드 레벨까지 설명해 주는 글이 별로 없었기 때문에 개인적으로 정리해 보겠습니다.
멀티 테넌시 아키텍처 중 멀티 데이터소스를 집중적으로 다룰 예정이고 기타 예외처리 및 인증/인가 설정은 주제에 벗어나기 때문에 생략하도록 하겠습니다. (구현한 소스 코드에서도 생략이 되어 있습니다.)
저도 처음 접하는 내용이기 때문에 틀린 내용이 있을 수 있으며 댓글로 지적 및 조언을 해주시면 감사하겠습니다!

 

멀티 테넌시란?

멀티 테넌시는 하나의 시스템 안에서 여러 개의 테넌트(사용자 그룹 또는 고객)를 동시에 지원할 수 있는 아키텍처입니다.
이는 클라우드 컴퓨팅에서 많이 사용되며, 각 테넌트는 자신만의 데이터와 설정을 가지고 독립적으로 시스템을 사용할 수 있습니다.
이를 통해 각 테넌트의 데이터와 프로세스가 서로 격리되어 보안과 안정성을 높일 수 있으며 SaaS(Software as a Service)와 같은 구독형 클라우드 서비스에서 적용됩니다.
멀티 테넌시 관련 자세한 설명은 아래 링크를 참고해주세요.
https://maily.so/saascenter/posts/0f0d2b0c

 

온프레미스 설치형 소프트웨어 성장은 멈추지 않았다

온프레미스 소프트웨어 시장 리포트, 인프라는 곧 유통, 멀티 테넌트 개념 설명

maily.so

 
멀티 테넌시를 적용하기 위해서는 각 테넌트의 데이터를 분리하는 동시에 다른 리소스는 최대한 많이 공유해야 합니다.
이를 달성하기 위한 대표적인 아키텍처 패턴은 아래와 같이 세 가지가 있으며 테넌트 간 데이터의 물리적 분리 정도가 다릅니다.

  • 테넌트를 데이터베이스 단위로 분리
  • 테넌트를 스키마 단위로 분리
  • 모든  테넌트 데이터가 동일 테이블에 저장되고 tenant_id 칼럼 기준으로 데이터 분리

 
테넌트를 데이터베이스 단위로 분리 (Database per Tenant)

 

https://callistaenterprise.se/blogg/teknik/2020/09/19/multi-tenancy-with-spring-boot-part1/

 
장점

  • 데이터를 확실하게 분리
  • 트래픽이 몰리더라도 데이터베이스 단위로 분산되어 부하가 덜함
  • 테넌트마다 별도 DMBS를 사용하는 경우 서비스가 지원하는 DB 벤더 중 하나를 선택 가능

단점

  • 테너트의 수에 비례하여 관리 포인트가 늘어나기 때문에 운영 비용 상승

 
테넌트를 스키마 단위로 분리 (Schema Per Tenant)

 

https://callistaenterprise.se/blogg/teknik/2020/09/19/multi-tenancy-with-spring-boot-part1/

 
장점

  • 테넌트 별로 데이터가 분리
  • 테넌트 별로 다른 데이터베이스 커넥션을 사용하도록 구현되므로 비즈니스 로직에 의존적이지 않음

 
단점

  • 단일 데이터베이스 내 스키마 단위로 분리되어 있으므로 하나의 테넌트에서 트래픽이 몰릴 경우 다른 테넌트에 영향을 끼칠 수 있음

 
단일 테이블 전략 (Shared Database, using a Discriminator Column)

https://callistaenterprise.se/blogg/teknik/2020/09/19/multi-tenancy-with-spring-boot-part1/

 
장점

  • tenant_id 칼럼 값을 기준으로 테넌트를 식별하므로 테넌트 추가 시 별도의 작업이 필요하지 않음
  • 비교적 구현하기 쉬움

 
단점

  • 모든 테넌트의 데이터가 하나의 테이블에 섞여있어 관리하기 어려움
  • 멀티테넌시 아키텍처에 의존하는 비즈니스 로직 작성 (tenantId를 파라미터로 전달하고 쿼리에서 WHERE절에 tenantId =? 와 같은 절을 항상 포함해야 함)
  • 테넌트마다 데이터 양과 사용량이 크게 다를 수 있어 효율적인 리소스 사용 계획을 세우기 어려움

 
이번 게시글에서는 첫 번째 전략 위주로 설명을 진행할 예정이며 MyBatis로 구현한 프로젝트는 동일 DB 벤더를 사용하는 데이터베이스 단위로 분리하는 방식으로 구현했으며 JPA로 구현한 프로젝트는 여러 DB 벤더를 사용할 수 있는 데이터베이스 단위로 분리하는 방식을 선택했습니다. (MyBatis는 MariaDB, JPA는 PostgreSQl과 MariaDB를 사용하는 예제를 준비했습니다.)

 

프로젝트 기술 스택 소개 및 전체적인 흐름

 
MyBatis 프로젝트

 

  • SpringBoot 2.7.9
  • Spring Web
  • MyBatis Framework
  • MariaDB Driver
  • Spring Data Jdbc

 
JPA 프로젝트

 

  • SpringBoot 2.7.9
  • Spring Web
  • Spring Data JPA
  • MariaDB Driver
  • PostgreSQL Driver
  • Liquibase Migration
  • Caffeine Cache 3.1.5

 
두 프로젝트의 구현 방법은 다르지만 전체적인 흐름은 아래와 같이 비슷합니다.
스프링 시큐리티 관련 구현은 하지 않았지만 흐름 파악을 위해 그림에서는 권한 분리를 한 것처럼 묘사했습니다.
 

 

  • admin 관리자가 테넌트를 추가하는데 이때 테넌트 ID와 해당 테넌트와 매핑되는 데이터 소스를 등록
  • 전달된 내용을 기반으로 데이터베이스를 생성하고 resource 폴더 내 DDL 정보를 기반으로 테이블 생성
  • 마스터 schema 혹은 database 내 위치한 data_source_config 테이블에 해당 정보 저장
  • 내부적으로 테넌트 ID를 key, 데이터소스 정보를 value로 가지는 map 혹은 cache를 업데이트
  • 테넌트가 header 정보 내 x-tenant-id key에 tenant id를 전달하면 인터셉터에서 tenantId를 꺼내서 ThreadLocal에 저장하고 앞서 업데이트한 map 혹은 cache로부터 해당 tenant id에 매핑된 DataSource와 연동하여 비즈니스 로직 수행 후 응답

 
위 흐름에서 고려해봐야 할 요소

  • 서버가 N중화되어 있을 경우 나머지 서버 내 map 혹은 cache를 어떻게 업데이트를 할 것인가?
    • 이 부분은 좀 더 생각해봐야 함
    • 하나의 서버에서 업데이트할 때 redis에 상태값을 업데이트하면 broadcasting 하도록 처리?
  • 회사 보안 정책에 따라 데이터베이스 자동 생성을 막을 수 있음
    • 이 부분은 속성 값을 기반으로 생성 유무를 제어하면 될 것 같음

 

MyBatis 프로젝트 주요 코드

MyBatis 프로젝트 내 주요 클래스로는 TenantInterceptor, TenantContextHolder, AbstractRoutingDataSource를 상속받은 DynamicRoutingDataSource 그리고 데이터베이스를 자동으로 생성해 주는 DBService가 있습니다.
우선 테넌트가 요청을 보냈을 때 흐름은 아래와 같습니다.

 

  • 테넌트가 Request Header에 x-tenant-id를 key로 테넌트 아이디를 보내면
  • TenantInterceptor에서 TenantContextHolder 내 ThreadLocal에 해당 테넌트 아이디를 세팅
  • DynamicRoutingDataSource의 determineCurrentLookupKey() 메서드에서 ThreadLocal에 세팅된 테넌트 아이디를 반환하면
  • AbstractRoutingDataSource의 resolvedDataSources Map 객체에서 해당 테넌트 아이디와 매핑된 DataSource를 찾아보고
  • 있으면 매핑된 데이터소스와 연동 없으면 디폴트 데이터소스와 연동 

 
순서대로 코드를 보면 아래와 같습니다.

 
TenantContextHolder

 

 

 
TenantInterceptor

 

 

 
DynamicRoutingDataSource
 

DynamicRoutingDataSource 코드를 보기 전에 우선 AbstractRoutingDataSource 코드를 확인해야 합니다.
AbstractRoutingDataSource 클래스 내 주요 메서드로는 afterPropertiesSet과 determineTargetDataSource가 있습니다.
 
AbstractRoutingDataSource
 

 
 
 
afterProprtiesSet() 메서드를 보면 targetDataSources Map 객체를 기반으로 resolvedDataSources Map 객체를 세팅하고 defaultTargetDataSource 세팅하는 것을 확인할 수 있습니다.
또한, determineTargetDataSources() 메서드를 보면 lookupKey를 기반으로 매칭되는 dataSource가 있으면 해당 데이터 소스를 반환하고 매칭되는 데이터소스가 없을 경우 디폴트 dataSource를 반환하는 것을 확인할 수 있습니다.
lookupKey와 매핑되는 dataSource가 없고 디폴트 dataSource도 없을 경우 예외를 던지는 것을 확인할 수 있습니다.
따라서 AbstractRoutingDataSource를 통해 멀티 데이터소스를 적용할 때는 디폴트 데이터소스를 지정해줘야 합니다.
즉, runtime에 테넌트를 동적으로 추가할 수 있지만 애플리케이션이 로딩되는 시점에는 이미 마스터 데이터베이스와 디폴트 데이터베이스가 생성이 되어 있어야 합니다.
마스터 데이터베이스에는 테넌트 정보를 저장할 수 있는 테이블이 있어야 하며 디폴트 데이터베이스에는 모든 테넌트가 동일하게 갖는 테이블이 생성되어 있어야 합니다.
그리고 data_source_config 테이블 내에는 디폴트 데이터 소스 정보가 저장되어 있어야 합니다.
각 데이터베이스의 DDL은 아래와 같습니다.
 
MariaDB > multi_tenant_master 데이터베이스 생성 및 data_source_config 테이블 생성

-- DROP TABLE
DROP TABLE IF EXISTS data_source_config;

-- CREATE TABLE
CREATE TABLE data_source_config
(
    TENANT_ID             VARCHAR(100) NOT NULL COMMENT '테넌트 ID',
    DRIVER_CLASS_NAME     VARCHAR(100) NOT NULL COMMENT 'DB 드라이버 클래스명',
    URL                   VARCHAR(500) NOT NULL COMMENT 'DB URL',
    USERNAME              VARCHAR(100) NOT NULL COMMENT 'DB 사용자ID',
    PASSWORD              VARCHAR(100) NOT NULL COMMENT 'DB 비밀번호',
    IS_DEFAULT            VARCHAR(1)   NOT NULL DEFAULT 'N' COMMENT '기본 설정 여부',
    PRIMARY KEY (TENANT_ID)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_unicode_ci COMMENT '멀티 테넌트 데이터베이스 정보';

 
 MariaDB > multi_tenant_default 데이터베이스 생성 및 product 테이블 생성

DROP TABLE IF EXISTS product;

CREATE TABLE product (
    id BIGINT auto_increment NOT NULL,
    product_name varchar(100) NOT NULL,
    quantity INT NOT NULL,
    created_by varchar(100) NOT NULL,
    CONSTRAINT tbl_product_PK PRIMARY KEY (id)
) ENGINE=InnoDB
  DEFAULT CHARSET=utf8mb4
  COLLATE=utf8mb4_general_ci;

 

 
MariaDB > multi_tenancy_master.data_source_config에 default 테이블 정보 추가
 

INSERT INTO multi_tenant_master.data_source_config
(TENANT_ID
, DRIVER_CLASS_NAME
, URL
, USERNAME
, PASSWORD
, IS_DEFAULT)
VALUES('default'
, 'org.mariadb.jdbc.Driver'
, 'jdbc:mariadb://localhost:3306/multi_tenant_default?allowMultiQueries=true'
, 'root'
, '1234'
, 'Y');

data_source_config에 multi_tenant_default 테이블 정보 insert

 
DynamicRoutingDataSource의 init() 메서드는 targetDataSource와 defaultTargetDataSource를 업데이트시켜 주는 메서드이며 애플리케이션이 로딩되는 시점에 AbstractRoutingDataSource에 등록을 해줘야 하는데 이는 DynamicRoutingDataSource를 스프링 컨테이너 내 Bean으로 등록할 때 등록시켜 주면 됩니다.
또한, 테넌트가 추가될 때마다 targetDataSource를 업데이트해줘야 하는데 이 과정을 refresh() 메서드가 수행합니다.
 
DynamicRoutingDataSource
 

 

@Bean
public DynamicRoutingDataSource dynamicRoutingDataSource(DataSourceRepository repository) {
    DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();
    routingDataSource.init(repository);

    return routingDataSource;
}

 

 
데이터베이스 커넥션 설정

 
멀티 데이터소스를 적용함에 따라 테넌트 정보는 언제나 동적으로 추가할 수 있어야 하므로 Master Database와의 연결은 항상 유지가 되어야 하지만 테넌트 데이터베이스의 경우 실제로 커넥션이 필요한 경우가 아니라면 데이터베이스 풀에서 커넥션을 점유하지 않고 실제로 필요한 시점에만 커넥션을 점유하도록 설정해줘야 합니다.
이를 위해 TenantDatabaseConfig에서는 LazyConnectionDataSourceProxy를 사용합니다.
 
따라서, MasterDatabaseConfig와 TenantDatabaseConfig을 모두 component으로 등록해줘야 하며 둘 다 DataSource를 Bean으로 등록해 주기 때문에 @Qualifer 애노테이션을 적용해줘야 합니다.
@Qualifer를 설정해주지 않을 경우 Ambiguous Mapping 오류가 발생합니다.

 

MasterDatabaseConfig

 

 

 

 

TenantDatabaseConfig

 

 

 
위처럼 마스터 데이터베이스와 테넌트 데이터베이스 설정이 분리시킬 경우 각 sqlSession이 어떤 mapper를 불러와야 하는지도 설정을 해줘야 합니다.
이에 따라 원래대로라면 MyBatis를 사용할 때는 repository가 없고 mapper만 쓰는데 해당 프로젝트에서는 설정이 분리되어 있기 때문에 mapper 레이어 상위에 repository 레이어가 존재하게 됩니다.
repository 레이어에서는 각 sqlSession과 적합한 mapper를 매핑하고 mapper 메서드를 bypass 하는 방식으로 구현했습니다,
 
DataSourceRepository
 

 
 
ProductRepository
 

 

 

 

테넌트 등록 시 자동 데이터베이스 생성 및 테이블 생성

 
해당 프로젝트에서는 admin이 테넌트를 등록할 경우 전달된 정보에 맞게 자동으로 데이터베이스 및 테이블을 생성하도록 구현했습니다.
해당 코드는 DBService.java에서 찾아볼 수 있으며 주요 메서드는 createDatabase()와 createObjects()입니다.
createDatabase()에서는 이름 그대로 데이터베이스를 생성하며 createObjects()에서는 resource 폴더 내 미리 정의된 DDL 파일을 input stream으로 불러와 테이블을 생성하는 메서드입니다.
 
DBService
 

 
MyBatis 프로젝트 소스 코드와 Postman Collection 공유
 

https://github.com/jaimemin/multi-datasource-mybatis

 

GitHub - jaimemin/multi-datasource-mybatis

Contribute to jaimemin/multi-datasource-mybatis development by creating an account on GitHub.

github.com

multi-tenant-mybatis.postman_collection
0.00MB

 

JPA 프로젝트 주요 코드

JPA 프로젝트에서도 주요 흐름은 MyBatis 프로젝트와 똑같습니다.
우선, 애플리케이션을 정상적으로 띄우기 위해서는 multi_tenancy_master 데이터베이스를 생성하고 public schema 내 아래 DDL을 실행하면 됩니다.
 
PostgreSQL > multi_tenancy_master 데이터베이스 생성 및 data_source_config 테이블 생성
 

create table data_source_config
(
    tenant_id         varchar not null
        constraint key_name
            primary key,
    url               varchar,
    db_name           varchar,
    username          varchar,
    password          varchar,
    driver_class_name varchar
);

alter table data_source_config
    owner to postgres;

 
다만, JPA를 사용하여 DataSource를 구성하기 때문에 hibernate에서 제공하는 인터페이스 구현체를 통해 멀티 테넌시를 사용합니다.
멀티 테넌시 관련해서 hibernate에서 제공하는 인터페이스는 아래와 같습니다.

  • org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl
  • org.hibernate.context.spi.CurrentTenantIdentifierResolver

 
CurrentTenantIdentifierResolver 구현체가 AbstractRoutingDataSource의 determineCurrentLookupKey() 메서드 역할을 하고 AbstractDataSourceBasedMultiTenantConnectionProviderImpl 구현체가 tenant id를 기반으로 데이터 소스를 매핑하는 역할을 합니다.
 
CurrentTenantIdentifierResolverImpl
 

 
 
DynamicDataSourceBasedMultiTenantConnectionProvider
 

 
 
selectAnyDataSource() 메서드는 테넌트 ID와 매핑되는 데이터소스가 없을 경우 디폴트 데이터소스를 반환하는 메서드이며 selectDataSource는 테넌트 ID와 매핑되는 데이터소스를 반환하는 메서드입니다.
MyBatis 프로젝트에서 적용했던 AbstractRoutingDataSource의 경우 내부적으로 Map 객체를 필드로 가지고 있고 해당 객체의 Getter/Setter 메서드를 제공했기 때문에 별도 cache를 선언할 필요가 없었지만 AbstractDataSourceBasedMultiTenantConnectionProviderImpl의 경우 클래스가 아니고 인터페이스이기 때문에 별도 필드가 없어 이와 동일한 역할을 하는 LoadingCache를 선언했습니다.
@PostConstruct 애노테이션을 통해 클래스가 생성된 후 캐시를 초기화하도록 하였고 런타임 시점에 테넌트가 추가될 때마다 캐시 내 테넌트가 추가되고 removalListener가 있어 설정한 만료시간 내 사용되지 않은 데이터소스를 닫아주도록 구현했습니다.
AbstractRoutingDataSource를 상속받을 경우 디폴트 테넌트 데이터소스가 무조건 등록이 되어있어야 했는데 hibernate에서 제공하는 인터페이스 구현체를 사용할 경우 디폴트 테넌트 데이터소스를 미리 등록할 필요가 없다는 장점이 있습니다.
마지막으로 createAndConfigureDataSource 메서드를 보면 HikariDataSourceBuilder를 통해 DataSource를 생성할 때 driverClassName도 등록해 주는 것을 볼 수 있습니다.
JPA 프로젝트의 경우 JPA의 장점을 살려 하나의 레포지토리로 여러 DB 벤더를 대응할 수 있도록 구현을 했습니다.
따라서 DataSource를 생성할 때 드라이버 클래스를 명시해줘야 하며 이는 드라이버 클래스를 명시해 줘야지만 hibernate에서 내부적으로 드라이버 클래스에 맞는 Dialect로 변환하여 쿼리를 호출하기 때문입니다.
driverClassName을 명시하지 않을 경우 yml 파일에 명시된 dialect로 설정되므로 mysql을 DBMS로 갖는 테넌트가 요청을 보낼 때 에러가 발생합니다.
 
고려할 사항

  • Jpa에서 제공하는 메서드 외 사용자가 직접 작성한 native query가 있을 경우 DB 벤더에 따라 sql grammar exception이 발생할 수 있습니다.

-> 이럴 경우 어쩔 수 없이 DB 벤더마다 별도 Persistence 설정을 구현하고 각각 repository를 생성해줘야 할 것 같습니다.

 
DataSource와 Persistence 설정

 
멀티 데이터소스 프로젝트이므로 해당 프로젝트에서도 MasterPersistenceConfig와 TenantPersistenceConfig를 분리해야 합니다.
다만 항상 연결을 유지하는 것은 마스터 데이터베이스이므로 DataSource 설정은 MasterDataSourceConfig만 구현해 주면 됩니다.
 
MasterDataSourceConfig
 

 
 
MasterPersistenceConfig
 

 
 
TenantPersistenceConfig
 

 
 
TenantPersistenceConfig 내 71번째 줄을 보면 MultiTenantStrategy를 설정할 수 있는 것을 확인할 수 있습니다.
해당 프로젝트에서는 Database per Tenant 전략을 취했기 때문에 MultiTenancyStrategy.DATABASE를 선택했고 해당 enum을 보면 앞서 설명한 전략들이 다 있는 것을 확인할 수 있습니다.
 

 
테넌트 등록 시 자동 데이터베이스 생성 및 테이블 생성

 
해당 프로젝트에서도 JDBC를 이용하여 데이터베이스를 생성하지만 테이블은 DB 형상관리 오픈소스인 Liquibase를 통해 생성했습니다. (자매품으로 flyway라는 오픈소스도 있습니다.)
JPA 프로젝트에서는 테넌트마다 DB 벤더가 다를 수 있고 Liquibase의 경우 DBMS에 종속적이지 않은 언어로 작업을 할 수 있기 때문에 Liquibase를 선택했습니다.
 
두 오픈소스의 자세한 내용은 아래 글들에 잘 정리되어 있으니 참고하시면 좋을 것 같습니다.
https://341123.tistory.com/20

 

DB 형상관리툴 비교 - Flyway와 Liquibase

DB형상관리툴? 테이블 생성, 수정, 삭제 및 기본 데이터 입력 등의 DB를 구성하는 SQL이력을 관리해주는 프로그램입니다. 테이블 단위로 SQL문을 관리해주는 것이 좋습니다. 아래 비교 예제를 통해

341123.tistory.com

 
 
https://giljae.com/2022/05/31/DB-%ED%98%95%EC%83%81-%EA%B4%80%EB%A6%AC%ED%88%B4.html

 

DB 형상 관리툴 - Giljae Joo (주길재)

프로젝트를 준비하고 있다. DB Schema가 중요한 부분이지만 형상 관리가 되어 있지 않다. 사람에 의해서 관리가 되고 있는 실정이다. 소스 코드는 형상 관리를 하고 있지만 DB Schema는 형상 관리를

giljae.com

 
Liquibase를 적용하기 위해서는 resources 폴더 하위에 db.changelog 디렉터리를 만든 뒤 아래의 두 yaml 파일을 생성해줘야 합니다.
product 테이블은 MyBatis 프로젝트와 동일한 테이블입니다.
 
db.changelog-tenant.yaml
 

databaseChangeLog:
  - include:
      file: db/changelog/db.changelog-tenant-1.0.yaml

 
db.changelog-tenant-1.0.yaml
 

databaseChangeLog:

- changeSet:
    id: product
    author: jaimemin
    changes:
    - createTable:
        tableName: product
        columns:
        - column:
            name: id
            type: BIGINT
            autoIncrement: true
            constraints:
              primaryKey: true
              primaryKeyName: branch_pkey
        - column:
            name: product_name
            type: VARCHAR(100)
            constraints:
              nullable: false
        - column:
            name: quantity
            type: INTEGER
            constraints:
              nullable: false
        - column:
            name: created_by
            type: VARCHAR(256)
    - sql:
        dbms: 'postgresql'
        sql: >-
            ALTER SEQUENCE product_id_seq RESTART WITH 1;

 
* DBMS가 postgresql일 경우 시퀀스를 생성하도록 적용했습니다.
 
Liquibase 관련 주요 클래스는 TenantLiquibaseConfig와 DynamicDataSourceBasedMultiTenantSpringLiquibase가 있습니다.
DynamicDataSourcebasedMultiTenantSpringLiquibase는 SpringLiquibase의 afterPropertiesSet() 메서드를 오버라이드하여 등록된 테넌트 데이터소스를 생성 및 형상 관리하는 역할을 수행합니다.
 
TenantLiquidbaseConfig
 

 
 
DynamicDataSourceBasedMultiTenantSpringLiquibase
 

 
 
이제 테넌트를 추가할 때 JDBC를 이용하여 데이터베이스를 생성한 뒤 오버라이딩한 afterPropertiesSet() 메서드를 호출하여 테넌트와 매핑된 데이터소스에 테이블을 생성할 수 있습니다.
 
DataSourceManagementService
 

 

JPA 프로젝트 소스 코드와 Postman Collection 공유

 

GitHub - jaimemin/multi-datasource-jpa

Contribute to jaimemin/multi-datasource-jpa development by creating an account on GitHub.

github.com

multi-tenant-jpa.postman_collection
0.00MB

 

참고

https://velog.io/@gaegulgaegul/Spring-Data-JPA-%EB%A9%80%ED%8B%B0-%ED%85%8C%EB%84%8C%EC%8B%9C

 

Spring Data JPA 멀티 테넌시

스프링 데이터 JPA를 사용한 Database per Multi Tenancy 구성 경험을 공유합니다.

velog.io

https://sup2is.github.io/2021/07/08/lazy-connection-datasource-proxy.html

 

Sup2's blog-LazyConnectionDataSourceProxy 알아보기

 

sup2is.github.io

https://callistaenterprise.se/blogg/teknik/2020/10/10/multi-tenancy-with-spring-boot-part4/

 

Dynamic Multi Tenancy with Spring Boot, Hibernate and Liquibase Part 4: Implement the Schema-per-tenant pattern using Hibernate

10 October 2020 // Björn Beskow In the last part, we implemented the Database-per-tenant pattern, and observed that it has limited scalability. In this part, we will tweak the solution and implement the Schema-per-tenant pattern in much the same way. Blog

callistaenterprise.se

https://sunitkatkar.blogspot.com/2018/05/adding-tenants-without-application.html

 

Adding tenants without application restart in SaaS style multi-tenant web app with Spring Boot 2 and Spring Security 5

A blog about software development. Java, Spring, Spring Boot, Spring Security, Salesforce APEX, Keycloak, Security

sunitkatkar.blogspot.com

https://stackoverflow.com/questions/28633759/hibernate-multi-tenancy-create-schema-during-runtime?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa 

 

Hibernate multi-tenancy create schema during runtime

I am setting up multi-tenant support for a java web application using hibernate 4 and spring 4. The default schema is created and set when the application starts. This schema works fine when not tr...

stackoverflow.com

https://blog.51cto.com/waxyz/5336941

 

Multi-tenant applications using Spring Boot, JPA, Hibernate and Postgres_源知原味的技术博客_51CTO博客

Multi-tenant applications using Spring Boot, JPA, Hibernate and Postgres 原创 源知原味Coder 2022-05-27 11:58:47 ©著作权 文章标签 ide spring hibernate 文章分类 spring boot 后端开发 ©著作权归作者所有:来自51CTO博客作者

blog.51cto.com

 

반응형