programing

멀티 테넌시(Multi-tenancy): Spring Data JPA로 여러 데이터 소스 관리

testmans 2023. 10. 2. 11:15
반응형

멀티 테넌시(Multi-tenancy): Spring Data JPA로 여러 데이터 소스 관리

여러 데이터 소스를 관리할 수 있는 서비스를 만들어야 합니다.이러한 데이터 소스는 앱을 처음 실행할 때 실제로 엔드포인트가 새로운 데이터베이스를 생성할 때 반드시 존재하는 것은 아니며, 저는 이러한 데이터 소스로 전환하여 데이터를 생성할 수 있기를 원합니다.

예를 들어, 제가 A, B, C 등 3개의 데이터베이스를 가지고 있다고 가정하고, 앱을 시작하고, D를 생성하는 엔드포인트를 사용하고, D를 사용하고 싶습니다.

그게 가능한가요?

다른 데이터 소스가 있는 경우 다른 데이터 소스로 전환하는 방법은 알고 있지만 현재로서는 요청을 가능하게 해 줄 솔루션을 찾을 수 없습니다.무슨 생각 있어요?

감사해요.

Spring Boot로 멀티 테넌시(Multi-tenancy)를 구현하려면 AbstractRoutingDataSource를 모든 '테넌시 데이터베이스'에 대한 기본 DataSource 클래스로 사용할 수 있습니다.

재정의해야 하는 CurrentLookupKey를 결정하는 추상적인 방법이 하나 있습니다.그것은 말해줍니다.AbstractRoutingDataSource현재 작업할 테넌트 데이터 소스를 제공해야 합니다.다중 스레드 환경에서 작동하므로 선택한 테넌트의 정보를ThreadLocal변수.

AbstractRoutingDataSource테넌트 데이터 소스의 정보를 개인에 저장합니다.Map<Object, Object> targetDataSources. 이 맵의 키는 테넌트 식별자(예: String type)와 테넌트 데이터 소스의 값입니다.테넌트 데이터 소스를 이 맵에 배치하려면 해당 세터를 사용해야 합니다.setTargetDataSources.

AbstractRoutingDataSource메서드와 함께 설정해야 하는 'default' 데이터 소스가 없으면 작동하지 않습니다.setDefaultTargetDataSource(Object defaultTargetDataSource).

테넌트 데이터 소스와 기본 데이터 소스를 설정한 후 메소드를 호출해야 합니다.afterPropertiesSet()말로 전하다AbstractRoutingDataSource상태를 업데이트합니다.

따라서 'Multi Tenant Manager' 클래스는 다음과 같습니다.

@Configuration
public class MultiTenantManager {

    private final ThreadLocal<String> currentTenant = new ThreadLocal<>();
    private final Map<Object, Object> tenantDataSources = new ConcurrentHashMap<>();
    private final DataSourceProperties properties;

    private AbstractRoutingDataSource multiTenantDataSource;

    public MultiTenantManager(DataSourceProperties properties) {
        this.properties = properties;
    }

    @Bean
    public DataSource dataSource() {
        multiTenantDataSource = new AbstractRoutingDataSource() {
            @Override
            protected Object determineCurrentLookupKey() {
                return currentTenant.get();
            }
        };
        multiTenantDataSource.setTargetDataSources(tenantDataSources);
        multiTenantDataSource.setDefaultTargetDataSource(defaultDataSource());
        multiTenantDataSource.afterPropertiesSet();
        return multiTenantDataSource;
    }

    public void addTenant(String tenantId, String url, String username, String password) throws SQLException {

        DataSource dataSource = DataSourceBuilder.create()
                .driverClassName(properties.getDriverClassName())
                .url(url)
                .username(username)
                .password(password)
                .build();

        // Check that new connection is 'live'. If not - throw exception
        try(Connection c = dataSource.getConnection()) {
            tenantDataSources.put(tenantId, dataSource);
            multiTenantDataSource.afterPropertiesSet();
        }
    }

    public void setCurrentTenant(String tenantId) {
        currentTenant.set(tenantId);
    }

    private DriverManagerDataSource defaultDataSource() {
        DriverManagerDataSource defaultDataSource = new DriverManagerDataSource();
        defaultDataSource.setDriverClassName("org.h2.Driver");
        defaultDataSource.setUrl("jdbc:h2:mem:default");
        defaultDataSource.setUsername("default");
        defaultDataSource.setPassword("default");
        return defaultDataSource;
    }
}

간단한 설명:

  • 지도를tenantDataSources로컬 테넌트 데이터 소스 스토리지로,setTargetDataSources세터;

  • DataSourceProperties properties테넌트 데이터베이스의 데이터베이스 드라이버 클래스 이름을 가져오는 데 사용됩니다.spring.datasource.driverClassName'application.properties'(예:org.postgresql.Driver);

  • 방법addTenant새 테넌트와 해당 데이터 소스를 로컬 테넌트 데이터 소스 스토리지에 추가하는 데 사용됩니다.방법 덕분에 바로 할 수 있습니다.afterPropertiesSet();

  • 방법setCurrentTenant(String tenantId)지정된 테넌트의 데이터 소스를 '전환'하는 데 사용됩니다.예를 들어 REST 컨트롤러에서 데이터베이스 작업 요청을 처리할 때 이 방법을 사용할 수 있습니다.요청에는 예를 들어 'tenantId'가 포함되어야 합니다.X-TenantId우리가 검색하고 이 방법에 넣을 수 있는 헤더.

  • defaultDataSource()는 작동 중인 SQL 서버에서 기본 데이터베이스를 사용하지 않도록 인메모리 H2 데이터베이스로 구축됩니다.

참고: 설정해야 합니다.spring.jpa.hibernate.ddl-auto에 매개 변수를 지정합니다.noneHibernate 데이터베이스 스키마를 변경하지 않도록 설정합니다.테넌트 데이터베이스 스키마를 미리 생성해야 합니다.

이 수업의 전체 예시와 더 많은 것들은 내 레포에서 찾을 수 있습니다.

업데이트됨

분기에서는 속성 파일 대신 테넌트 DB 속성을 저장하기 위해 전용 데이터베이스를 사용하는 예를 보여 줍니다(아래 @MarcoGustavo의 질문 참조).

언급URL : https://stackoverflow.com/questions/49759672/multi-tenancy-managing-multiple-datasources-with-spring-data-jpa

반응형