Spring에 Multidatabase 적용하고 트렌젝션 묶어보기! (1 / 2)

Coen·2022년 10월 17일
1

Multidatabase

목록 보기
1/2

지난주 원티드에서 진행하는 프리온보딩 백엔드 챌린지 10월에서 CQRS(Command and Query Responsibility Segregation) 라는 용어를 처음으로 들어보았다.

기존의 아키텍쳐에서는 하나의 데이터베이스에서 Read와 Create, Update, Delete를 수행하게 된다.
하지만 어플리케이션이 복잡해지면 READ시에 많은 SELECT를 하게 되어 데이터베이스에 무리를 주거나 성능이 저하될 수 있다.

CQRS는 이러한 문제를 해결하기 위해 Create, Update, Delete 작업을 하는 Command와
READ작업만 수행하는 Query로 구분하여 작업을 진행합니다.

또한 더 Write DB와 Read DB를 더 구분하기 위하여 관계형 데이터베이스와 noSQL을 함께 사용하는 방법도 있다고 합니다.

RDB에 Create, Update, Delete를 수행하고, NoSQL에 변경, 입력된 데이터를 취합하여 원하는 형태의 noSQL을 생성하여 insert를 수행한다. 이렇게 되면, 관계형 데이터베이스에서 Join이 발생하는 쿼리들을 수행할 때 보다 더 빠른 속도와 더 적은 부하를 받게 된다고 한다.

위의 CQRS를 적용해보기 이전에 Spring에서 Database를 두개 적용하는 방법을 선행해서 학습하게 되었다.

이 글은 아래의 유튜브를 보고 실습한 것으로, 궁금하신분들은 아래 유튜브를 참고해주세요!
Youtube - J108. Spring JPA Multiple Databases(Seungchul Park)

작업 환경

- IntelliJ
- DBeaver
- springboot 2.7.4
- maven
- google-collection 1.0
- docker 20.10.17
- mysql Ver 8.0.30 for Linux

데이터베이스를 두개 등록

docker run -d -p 13306:3306 -v wp-db-vol:/docker/mysql_test1 -e MYSQL_ROOT_PASSWORD=password --name mysql_test1 mysql --character-set-server=utf8 --collation-server=utf8_unicode_ci
docker run -d -p 23306:3306 -v wp-db-vol:/docker/mysql_test2 -e MYSQL_ROOT_PASSWORD=password --name mysql_test1 mysq2 --character-set-server=utf8 --collation-server=utf8_unicode_ci

docker에서 실행한 mysql들이 각각의 실행환경으로 동작하는지 확인해보고싶었다 (눈으로 봐야 안심되는 타입..)

확인을 완료했으니 본격적으로 데이터베이스들을 연결시켜 보자!


docker에서 각각의 환경을 13306, 23306 port에 매핑하였으므로 데이터베이스를 두개 연결했다.


이제 데이터베이스를 설정해보자!

import com.google.common.collect.ImmutableMap;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@ConfigurationProperties(prefix = "spring.db1.datasource")
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactory1",
        transactionManagerRef = "transactionManager1",
        basePackages = {"com.database.multidatabase.db1.repository"}
)
public class DbConfig1 extends HikariConfig {

    @Bean
    public DataSource dataSource1() {
        return new LazyConnectionDataSourceProxy(new HikariDataSource(this));
    }

    @Bean
    public EntityManagerFactory entityManagerFactory1() {
        JpaVendorAdapter vendorAdapter =new HibernateJpaVendorAdapter();

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(this.dataSource1());
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaPropertyMap(ImmutableMap.of(
                "hibernate.hbm2ddl.auto", "update",
                "hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect",
                "hibernate.show.sql", "true"
        ));
        factory.setPackagesToScan("com.database.multidatabase.db1.domain");
        factory.setPersistenceUnitName("db1");
        factory.afterPropertiesSet();

        return factory.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager1() {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(entityManagerFactory1());
        return tm;
    }
}
  • @configuration
    - 설정파일임을 선언하고 Bean을 등록한다.
  • @ConfigurationProperties
    - .yml이나 .properties와 같은 외부 설정파일로 외부화 하는 설정이다.
    • (prefix = "spring.db1.datasource") 를 통해 yml 파일에서
      spring:
        db1:
          datasource: 
      의 형태로 사용 가능하다.
  • @EnableJpaRepositories
    - 보통 SpringBoot를 사용한다면 기본적으로 @SpringBootApplication 에 선언되어 있어서 직접 사용할 일이 없지만, 여기서는 직접 데이터베이스 설정을 하기에 사용했다.
    • entitymanagerfactoryRef 와 transactionManagerRef 를 설정파일에서 Bean으로 등록한 객체로 매핑해주고,
    • basePackages 에 Scan할 패키지들을 입력한다.

1부는 여기서 끝으로 하고 이후 작업은 2부에서 마저 쓰도록 하겠습니다.

틀리거나 잘못된 부분이 있다면 bht9011@gmail.com 로 제보 부탁드립니다.
읽어주셔서 감사합니다.

profile
백엔드 프로그래머

0개의 댓글