기존에 운영중인 spring boot으로 만든 msa중의 하나가

단일 datasource를 운영중이었는데 다른 datasource를 참조할 일이 생겼다

기존에 jpa를 쓰지 않는건 경험이 있는데 jpa까지 연동 되어있던부분을 바꾸려고 하니 시행착오가 많았어서 결국 정리를 해본다.

 

1. application.yml에 datasource부분 추가

기존

datasource:

   url : jdbc:oracle:thin  --> jdbc-url로 변경
    ...

datasource-dev:

    jdbc-url : jdbc:oracle:thin
   ...

 

똑같은 형식으로 추가해준다. (이럴경우 기존설정에 혹시 url이라는 이름으로 jdbc url을 설정했다면 원래 설정도 jdbc-url이라고 바뀌어야한다)

 

2. dataSource config파일 생성

config경로에 datasource별 config를 만들어야한다.

이번경우는 기존에 jpa를 이미 연동시켜 놓아서 이부분도 같이 처리를 해줘야 했다.

기존 사용 datasource를 primary로 세팅한다.

 

PrimaryDataSourceConfig.java

 

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = {"com.example.xxx.repository"},  // JPA가 적용될 repository경로지정
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager"
)
@EntityScan(basePackages = {"com.example.xxx.entity"})  // 엔티티 패키지 경로 지정
public class PrimaryDataSourceConfig {

@Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

@Primary
    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            @Qualifier("primaryDataSource") DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setDataSource(dataSource);
        entityManagerFactory.setPackagesToScan("com.example.xxx.entity" ); // 엔티티 패키지 경로 지정
        entityManagerFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        Map<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        entityManagerFactory.setJpaPropertyMap(properties);

        return entityManagerFactory;
    }

@Primary
    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager primaryTransactionManager(
            @Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
    
@Primary
    @Bean
public SqlSessionFactory primarySqlSessionFactory(DataSource primaryDataSource, ApplicationContext applicationContext) throws Exception 
{
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 
sqlSessionFactoryBean.setDataSource(primaryDataSource); 
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mapper/primary_*/*.xml")); 
return sqlSessionFactoryBean.getObject(); 
}

@Primary
@Bean
public SqlSessionTemplate primarySqlSessionTemplate(SqlSessionFactory primarySqlSessionFactory) throws Exception 
{
return new SqlSessionTemplate(primarySqlSessionFactory); 
}
}

 

위처럼 설정하면 된다.

위의 세개 설정으로 기존 jpa도 문제없이 동작하는것을 확인하였다.

 

아래 두개는 mybatis도 같이 사용 할 경우 같이 설정 해줘야하며

@Primary 어노테이션을 빼먹으면 datasource가 2개라는 에러를 내면서 run이 되지 않는다.

꼭 붙여주도록 하자

 

그리고 mybatis의 mapperLocation을 설정하는 부분이 있는데 위처럼 resource/mapper/primary_*의 하위에 있는 mapper를 매핑시켜 주었다.

 

SecondaryDataSourceConfig.java 
@Configuration
public class SecondaryDataSourceConfig {
@Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource-dev")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondarySqlSessionFactory")
    public SqlSessionFactory secondarySqlSessionFactory(
            @Qualifier("secondaryDataSource") DataSource dataSource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setMapperLocations(applicationContext.getResources("classpath:mapper/secondary*/*.xml")); 
        return sessionFactory.getObject();
    }

    @Bean(name = "secondarySqlSessionTemplate")
    public SqlSessionTemplate secondarySqlSessionTemplate(
            @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

이제 새로 추가한 datasource-dev도 같이 datasource를 생성하였다.
mapper 설정도 primary와 동일한 방식으로 따로 구분하여서 매핑해주었다.

 

각각 생성한 Template명을 repository에서 불러서 매핑시켜주면 끝이다.

primary에는 제일 하단 primarySqlSessionTemplate 이란 이름으로

secondary는 @Bean(name = "secondarySqlSessionTemplate") 으로 명명하였지만 primary의 예시로 볼때

또는 경험상 메소드 명으로 자동 매핑되는것 같다

 

Repository에서 sqlSessionTemplate를 사용할때

@Repository
public class SecondaryRepository {

    @Autowired
    @Qualifier(value = "secondarySqlSessionTemplate")
    private SqlSessionTemplate sqlSession;

 

    public List<SampleDTO> getData(SampleDTO dto) {
        return sqlSession.selectList("secondaryMapper.getData", dto);
    }

    ....

위의 @Qualifier를 통해서 입맛대로 datasource를 사용할 수 있으며

@Qualifier를 사용하지 않으면 자동으로 Primary로 선언했던 primary datasource와연동된 sessionTemplate와 연동된다

 

끝..

Posted by emodent
,