[Java/Spring Boot] JdbcTemplate으로 여러 데이터베이스 연결하기

2025. 9. 14. 20:42·개발 (Development)/Java

한 프로젝트에서 하나의 데이터베이스만 다루다가, 새로운 데이터베이스가 추가되면 기존 구조를 확장해야 합니다. 이 글에서는 JdbcTemplate를 활용해 여러 개의 데이터베이스를 연결하고 선택적으로 실행하는 과정을 정리합니다.

문제 정의

  • 기본적으로 JdbcTemplate는 하나의 DataSource를 참조하여 단일 데이터베이스에 접근합니다.
  • 새로운 데이터베이스를 연결해야 할 때, 별도의 설정과 JdbcTemplate 등록이 필요합니다.
  • SQL 실행기를 공통화하여 코드 중복을 줄이고, 대상 DB만 선택해서 실행할 수 있어야 합니다.

DataSource 등록

Spring Boot에서는 DataSourceProperties를 통해 손쉽게 데이터소스를 생성할 수 있습니다. 데이터베이스마다 접두어를 달리 설정하면 여러 개의 DataSource를 만들 수 있습니다.

datasource:
  main:
    url: jdbc:mysql://localhost:3306/maindb
    username: main_user
    password: main_pass
    driver-class-name: com.mysql.cj.jdbc.Driver

  analytics:
    url: jdbc:mysql://localhost:3306/analyticsdb
    username: analytics_user
    password: analytics_pass
    driver-class-name: com.mysql.cj.jdbc.Driver
@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("datasource.main")
    public DataSourceProperties mainProps() {
        return new DataSourceProperties();
    }

    @Bean(name = "mainDataSource")
    public DataSource mainDataSource() {
        return mainProps().initializeDataSourceBuilder().build();
    }

    @Bean
    @ConfigurationProperties("datasource.analytics")
    public DataSourceProperties analyticsProps() {
        return new DataSourceProperties();
    }

    @Bean(name = "analyticsDataSource")
    public DataSource analyticsDataSource() {
        return analyticsProps().initializeDataSourceBuilder().build();
    }
}

JdbcTemplate 등록

각 데이터소스마다 JdbcTemplate를 등록합니다.

@Configuration
public class JdbcTemplateConfig {

    @Bean(name = "mainJdbcTemplate")
    public JdbcTemplate mainJdbcTemplate(@Qualifier("mainDataSource") DataSource ds) {
        return new JdbcTemplate(ds);
    }

    @Bean(name = "analyticsJdbcTemplate")
    public JdbcTemplate analyticsJdbcTemplate(@Qualifier("analyticsDataSource") DataSource ds) {
        return new JdbcTemplate(ds);
    }
}

데이터베이스 식별 Enum

어떤 데이터베이스를 사용할지 구분할 수 있도록 Enum을 정의합니다.

public enum DbTarget {
    MAIN,
    ANALYTICS
}

SqlExecutor 구현

Map<DbTarget, JdbcTemplate>를 주입받아, 호출 시 원하는 DB에 SQL을 실행할 수 있도록 작성합니다.

@Component
public class SqlExecutor {

    private final Map<DbTarget, JdbcTemplate> templates;

    public SqlExecutor(@Qualifier("mainJdbcTemplate") JdbcTemplate main,
                       @Qualifier("analyticsJdbcTemplate") JdbcTemplate analytics) {
        this.templates = Map.of(
            DbTarget.MAIN, main,
            DbTarget.ANALYTICS, analytics
        );
    }

    public void runSqlFile(String sqlFilePath, DbTarget target) throws Exception {
        JdbcTemplate jdbcTemplate = templates.get(target);
        if (jdbcTemplate == null) {
            throw new IllegalArgumentException("JdbcTemplate not found for " + target);
        }

        Resource resource = new ClassPathResource(sqlFilePath);
        try (InputStream is = resource.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {

            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                String t = line.trim();
                if (t.isEmpty() || t.startsWith("--")) continue;
                sb.append(t).append('\n');
                if (t.endsWith(";")) {
                    String sql = sb.toString().trim();
                    sql = sql.substring(0, sql.length() - 1);
                    if (!sql.isEmpty()) jdbcTemplate.execute(sql);
                    sb.setLength(0);
                }
            }
            if (sb.length() > 0) {
                jdbcTemplate.execute(sb.toString());
            }
        }
    }
}

서비스와 컨트롤러에서 활용

서비스 계층에서는 실행 성공 여부를 반환하도록 구성합니다.

@Service
public class SqlService {

    private final SqlExecutor sqlExecutor;

    public SqlService(SqlExecutor sqlExecutor) {
        this.sqlExecutor = sqlExecutor;
    }

    public boolean updateAnalyticsData() {
        try {
            sqlExecutor.runSqlFile("sql/update_analytics.sql", DbTarget.ANALYTICS);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

컨트롤러에서는 API 요청에 대해 성공 여부를 JSON으로 반환합니다.

@RestController
@RequestMapping("/sql")
public class SqlController {

    private final SqlService sqlService;

    public SqlController(SqlService sqlService) {
        this.sqlService = sqlService;
    }

    @PostMapping("/update-analytics")
    public ResponseEntity<Map<String, Object>> updateAnalytics() {
        boolean success = sqlService.updateAnalyticsData();
        Map<String, Object> result = new HashMap<>();
        result.put("success", success);
        result.put("message", success ? "성공" : "실패");
        return ResponseEntity.ok(result);
    }
}

정리

  • DataSourceProperties와 DataSource를 DB별로 분리하여 등록한다.
  • 각 DB마다 JdbcTemplate를 만들어 사용한다.
  • SqlExecutor에서 Map<DbTarget, JdbcTemplate> 구조를 사용하면 DB 선택이 단순하고 확장성이 좋다.
  • 서비스와 컨트롤러에서 성공 여부를 반환해 클라이언트가 실행 결과를 쉽게 확인할 수 있다
반응형

'개발 (Development) > Java' 카테고리의 다른 글

[Java] 객체 리스트를 특정 속성으로 정렬하는 방법  (1) 2025.10.06
[Java/Spring Boot] "No thread-bound request found" 에러 원인과 해결법  (0) 2025.09.19
[Java/Spring Boot] Spring Boot에서 OAuth2 인증 401 오류 해결하기  (0) 2025.09.14
[Java] JPA에서 DTO는 Interface로 구현할까? Class로 구현할까?  (4) 2025.08.03
[Java] Interface란? 클래스와 다른 점은?  (0) 2025.08.03
'개발 (Development)/Java' 카테고리의 다른 글
  • [Java] 객체 리스트를 특정 속성으로 정렬하는 방법
  • [Java/Spring Boot] "No thread-bound request found" 에러 원인과 해결법
  • [Java/Spring Boot] Spring Boot에서 OAuth2 인증 401 오류 해결하기
  • [Java] JPA에서 DTO는 Interface로 구현할까? Class로 구현할까?
LoopThinker
LoopThinker
모르는 것을 알아가고, 아는 것을 더 깊게 파고드는 공간
  • LoopThinker
    CodeMemoir
    LoopThinker
  • 전체
    오늘
    어제
    • 분류 전체보기 (231)
      • 개발 (Development) (165)
        • Algorithm (1)
        • Angular (1)
        • AWS (6)
        • DeepSeek (2)
        • Docker (7)
        • Git (3)
        • Java (34)
        • JavaScript (4)
        • Kafka (5)
        • Kubernetes (4)
        • Linux (7)
        • PostgreSQL (38)
        • Python (31)
        • React (3)
        • TypeScript (3)
        • Vue.js (5)
        • General (11)
      • 데이터 분석 (Data Analysis) (1)
      • 알고리즘 문제 풀이 (Problem Solving.. (27)
      • 자격증 (Certifications) (24)
        • ADsP (14)
        • 정보처리기사 (4)
        • Linux Master (5)
        • SQLD (1)
      • 기술 동향 (Tech Trends) (11)
      • 기타 (Others) (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준자바
    리눅스 마스터 2급
    AWS
    Vue.js
    springboot
    PostgreSQL
    MyBatis
    오답노트
    Spring boot
    JSON
    백준
    Linux master
    pandas
    리눅스 마스터 2급 2차
    백준알고리즘
    데이터분석
    java
    deepseek
    docker
    자바
    python
    Linux
    javascript
    DevOps
    JPA
    ADsP
    백준온라인저지
    timescaledb
    Kubernetes
    Kafka
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
LoopThinker
[Java/Spring Boot] JdbcTemplate으로 여러 데이터베이스 연결하기
상단으로

티스토리툴바