[JPA] 스프링 JPA 다중DB 사용하기

2022. 11. 28. 16:42Web/spring-boot

@Configuration
@RequiredArgsConstructor
@EnableJpaRepositories(
        basePackages = {"프로젝트 패키지 경로"},
        entityManagerFactoryRef = "dbEntityManager",
        transactionManagerRef = "dbTransactionManager"
)
@EnableTransactionManagement
public class DbConfig {

    private final DbProperties dbProperties;
    private final DbWriteProperties dbWriteProperties;

    @Value("propertise에 입력된 값")
    private boolean showSql;

    @Bean
    public JPAQueryFactory jpaQueryFactory(@Qualifier("dbEntityManager") EntityManager dbEntityManager) {
        return new JPAQueryFactory(dbEntityManager);
    }

    @Primary
    @Bean(name = "dbEntityManager")
    public LocalContainerEntityManagerFactoryBean dbEntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(cellookRoutingDataSource());
        em.setPackagesToScan("엔티티 경로");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setShowSql(showSql);
        vendorAdapter.setDatabasePlatform("방언경로 (Dialect)");
        em.setJpaVendorAdapter(vendorAdapter);

        Map<String, Object> jpaProperties = new HashMap<>();
        jpaProperties.put("hibernate.physical_naming_strategy", CustomJpaNamingStrategy.class.getName());
        jpaProperties.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
        em.setJpaPropertyMap(jpaProperties);
        return em;
    }

    @Primary
    @Bean("RoutingDataSource")
    public DataSource RoutingDataSource() {
        HikariDataSource masterDataSource = dbWriteProperties.getHikariConfig();
        HikariDataSource slaveDataSource = dbProperties.getHikariConfig();
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("MASTER", masterDataSource);
        dataSourceMap.put("SLAVE", slaveDataSource);
        DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();
        routingDataSource.setTargetDataSources(dataSourceMap);
        routingDataSource.setDefaultTargetDataSource(masterDataSource);
        return routingDataSource;
    }

    @Primary
    @Bean("RoutingLazyDataSource")
    public DataSource RoutingLazyDataSource(@Qualifier("RoutingDataSource") DataSource dataSource) {
        return new LazyConnectionDataSourceProxy(dataSource);
    }

    @Primary
    @Bean(name = "dbTransactionManager")
    public PlatformTransactionManager dbTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(dbEntityManager().getObject());
        return transactionManager;
    }
}

 

- 다중 DB를 연결할 때 중요한 부분

  • 반드시 하나의 데이터베이스에는 @Primary 어노테이션을 붙여주어야한다. 그래야 @Autowired를 사용할 때 여러 개의 데이터베이스에서 우선순위를 갖는 @Primary 어노테이션이 붙여져 있는 데이터베이스로 연동되거나 @Qualifier로 의존성이 주입된 빈으로 연동된다.
  • DataSource : application.yml 파일이나 application.properties 파일에 정의된 내용과 연동됨.
  • PlatformTransactionManager : 트랜젝션에서 예외가 발생하면 롤백되는 기능을 가짐
  • LocalContainerEntityManagerFactoryBean : JPA 엔티티 설정
  • application.yml 파일에 db관련정보를 적어놓고 데이터베이스 별로 datasource명 밒 설정을 다르게 주입시킬 수 있다.
spring:
  h2:
    console:
      enabled: true
      path: /h2-console

  register:
    datasource4:
      jdbc-url: jdbc:h2:mem://localhost/~/register
      driver-class-name: org.h2.Driver
      username: sa
      password:

  file:
    datasource1:
      jdbc-url: jdbc:h2:mem://localhost/~/file
      driver-class-name: org.h2.Driver
      username: sa
      password:

  netstat:
    datasource2:
      jdbc-url: jdbc:h2:mem://localhost/~/netstat
      driver-class-name: org.h2.Driver
      username: sa
      password:

  process:
    datasource3:
      jdbc-url: jdbc:h2:mem://localhost/~/process
      driver-class-name: org.h2.Driver
      username: sa
      password: