0+ 스프링/0 + SpringBoot(스프링부트)

JPA 다중 DataSource 설정

힘들면힘을내는쿼카 2022. 1. 8. 18:21
728x90
반응형

 

스프링 부트를 이용하면 application.properties 또는 application.yml에 설정하여 db에 쉽게 연결 할 수 있다.

하지만 n개의 db에 접속하기 위해서는 application.properties, application.yml에 설정한 것에 따라 bean에 직접 등록해야한다.

 

 

글쓴이는 yml을 이용하여 2개의 mariadb에 연결하는것을 포스팅 하겠습니다.

 

1. application.yml 설정

spring:
  jpa:
    hibernate:
      ddl-auto: validate
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    properties:
      hibernate:
        #       show_sql: trues
        format_sql: true
        dialect: org.hibernate.dialect.MariaDB103Dialect

primary:
  datasource:
    url: jdbc:mariadb://ip입력:포트번호/DB이름
    username: "아이디 입력"
    password: "패스워드 입력"
    driver-class-name: org.mariadb.jdbc.Driver

secondary:
  datasource:
    url: jdbc:mariadb://ip입력:포트번호/DB이름
    username: "아이디 입력"
    password: "패스워드 입력"
    driver-class-name: org.mariadb.jdbc.Driver

logging:
  level:
    org.hibernate.SQL: debug
    org.hibernate.type: trace
728x90

 

2. Bean 등록

config 패키지

상위 패키지 아래에 config 패키지를 만들어 다음과 같이 2개의 config class를 만들었다.

 

2-1) PrimaryDataSourceConfig class

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager",
        basePackages = { "repository가 있는 패키지 경로" })
public class PrimaryDataSourceConfig {

    @Primary
    @Bean
    @ConfigurationProperties("primary.datasource")
    public DataSourceProperties primaryDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean
    @ConfigurationProperties("primary.datasource.configuration")
    public DataSource primaryDataSource(@Qualifier("primaryDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder,
                                                                              @Qualifier("primaryDataSource") DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("도메인이 클래스가 있는 패키지 경로")
                .persistenceUnit("primaryEntityManager")
                .build();
    }

    @Primary
    @Bean
    public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

 

2-2) SecondaryDataSourceConfig class

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "secondaryEntityManagerFactory",
        transactionManagerRef = "secondaryTransactionManager",
        basePackages = { "repository가 있는 패키지 경로" })
public class SecondaryDataSourceConfig {

    @Bean
    @ConfigurationProperties("secondary.datasource")
    public DataSourceProperties secondaryDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.configuration")
    public DataSource secondaryDataSource(@Qualifier("secondaryDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder,
                                                                                @Qualifier("secondaryDataSource") DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("domain이 있는 패키지 경로")
                .persistenceUnit("secondaryEntityManager")
                .build();
    }

    @Bean
    public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

 

반응형

 

3. repository class

3-1) primary datasource에 연결해야하는 repository class

@Repository
@RequiredArgsConstructor
public class FaultJpaRepository implements FaultRepository {

    @PersistenceContext(unitName = "primaryEntityManager")
    private EntityManager em;
    
    @Overide
    public Long save(Member member)
    {
    	return em.persist(member);
    }
}

 

3-2) secondary datasource에 연결해야하는 repository class

@Repository
@RequiredArgsConstructor
public class PMSJpaRepository implements PMSRepository {

    @PersistenceContext(unitName = "secondaryEntityManager")
    private EntityManager em;

    @Override
    public void save(TB_PMS tb_pms)
    {
    	em.persist(tb_pms);
    }
		
    @Override
    public TB_PMS findById(String pms_id) {
        return em.find(TB_PMS.class, pms_id);
    }
}

 

 


 

위와같이 코드를 작성하고 나서 Service class에서 secondaryEntityManager를 사용하면 Transaction이 발생하지 않은 경우가 생겼다.

문제를 해결하기 위해서는 @Transactional(value = "secondaryTransactionManager") 어노테이션에 다음과 같이 코드를 작성해야 한다..!

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PMSService {

    private final PmsJpaRepository pmsJpaRepository;

    @Transactional(value = "secondaryTransactionManager")
    public void save(TB_PMS tb_pms)
    {
        pmsJpaRepository.save(tb_pms);
    }
}

 

감사합니다.

 

 

728x90
반응형