_

Always be tactful

성장 과정/인사이트

Spring Boot에서 JPA로 Docker MySQL 연동하기

tact 2025. 5. 22. 05:22

들어가며

자바는 프로그래밍 언어고, 스프링은 자바 기반 웹 애플리케이션 프레임워크다.

그런 스프링을 더 쉽게 쓰도록 돕는 툴킷이 스프링 부트다.

 

▼ 과거 배포 과정 (대략적)

더보기
  1. WAS 설치 (서버): 톰캣 같은 WAS를 OS에 설치하고 직접 설정
  2. IDE 내 개발: 이클립스 같은 IDE에서 복잡한 코딩 후 컴파일
  3. WAR 생성 (파일): 애플리케이션을 .war(웹 아카이브) 파일로 패키징
  4. WAR 배포: 톰캣 같은 WAS의 'webapps' 폴더에 넣거나 직접 업로드하여 배포
  5. 웹 앱 실행: WAS가 WAR 안에 들어있는 웹 애플리케이션을 풀어 서버 구동

▼ 스프링 부트 도입 후

더보기

WAS 직접 설치 및 설정

→ WAS(톰캣)을 내장 서버로 포함하여 바로 실행 가능

WAR 파일 생성 후 WAS에 배포

→ 실행 가능한 JAR 파일 하나만 있으면 충분

스프링 부트는 애플리케이션을 빠르게 만들고 실행할 수 있게 해주는 프레임워크라고 이해하자. 웹 서버를 띄우고, DB를 연결하고, REST API 만드는 등 여러 작업을 간단하게 만들어준다. 쉽게 말해 개발자가 기능 구현에 집중할 수 있도록 복잡한 설정을 자동으로 해주는 녀석이다.

그래서, JPA는 뭔데

JPA는 SQL 대신 자바 코드로 DB를 다루도록 해주는 기술이다.

 

풀 네임은 Java Persistence API.

자바에서 DB와 객체를 연결하는 기술, 즉 ORM이다.

DB의 테이블과 자바 클래스(entity)를 매핑해서, DB 조작을 자바 코드로 할 수 있게 만든다. 덕분에 SQL문을 직접 작성하지 않고 객체를 통해 DB를 다룰 수 있다. 조금 더 정밀하게 말하면 JPA는 스펙이고, 실체 구현체로는 Hibernate 등이 있다.

 

Gradle 기준 JPA 적용하기 (MySQL)

# build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.mysql:mysql-connector-j' # MySQL 드라이버
}

build.gradle에 의존성을 추가하자.

 

참고로 '그룹ID:아티팩트ID:버전'은 Gradle에서 의존성 라이브러리를 지정하는 방식이다.

com.mysql이 그룹ID(보통 회사/조직 이름)에 해당하고, mysql-connector-j가 아티팩트ID(라이브러리 이름)에 해당한다. *버전 부분이 빠진 이유는 스프링 부트가 버전 관리를 해주기 때문이다.

드라이버란 운영체제나 프로그램이 특정 장치나 시스템에 접근할 수 있게 해주는 중간 소프트웨어다. MySQL JDBC 드라이버는 자바 애플리케이션이 MySQL과 통신할 수 있도록 도와주는 일종의 통역기인 것이다.
Gradle에서 의존성을 설정할 때 implementation, compileOnly, runtimeOnly 같은 키워드가 있는데 그중 'runtimeOnly'는 실행할 때만 필요한 라이브러리를 뜻한다. 예를 들어, MySQL 드라이버는 우리가 직접 호출할 일이 없고, 앱이 실행될 때 내부적으로만 사용되기 때문에 runtimeOnly로 설정한다. (*JPA의 Hibernate가 내부적으로 JDBC를 통해 알아서 불러와 사용한다.)
# application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/<DB 이름>
    username: <사용자 이름>
    password: <사용자 비밀번호>
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true # 쿼리 로그 확인 목적

application.yml에 DB 연결 설정을 추가하자.

(*도커 컴포즈로 띄운 거라면 localhost 대신 호스트명을 적어야 한다.)

spring.jpa.hibernate.ddl-auto 옵션에는 create, create-drop, update, validate, none이 있다. 개발 초기엔 create/create-drop을 사용하고, 개발 단계에서는 update, 운영 단계에서는 안전성을 생각해 validate을 선호한다. (테스트가 끝난 경우 none)
참고로 driver-class-name은 생략 가능하다. 스프링 부트는 DB URL을 보면 자동으로 적절한 드라이버 클래스를 찾아준다.

 

민감정보 환경변수로 빼기

DB 접속 권한만으로도 모든 데이터 삭제/유출이 가능하다.

특히 *AWS RDS 같이 외부에 열려있는 DB라면 더더욱 위험하다.

*Amazon Web Services에서 제공하는 Relational Database Service

물론 지금의 나는 도커로 MySQL을 로컬에 띄워 사용하는 로컬 개발 환경이다. 즉, application.yml에 민감정보를 포함해 깃허브에 올려버려도 단지 각자의 로컬 환경에서 띄우는 도커 컨테이너용 MySQL 계정 정보라서 아무 의미 없다. 그래도 습관이 중요하니까 이참에 적용해 보자. (여러 환경 구분이 필요한 상황에서도 좋다. Ex. dev/prod/test)

 

1. 로컬 개발용으로 .env 파일을 설정하자.

# .env

DB_USERNAME=junIsTheBestDev
DB_PASSWORD=superSecret123!

프로젝트 루트에 .env 파일을 만들어서 변수를 저장하고, application.yml에서는 해당 변수를 참조하는 방식이다.

# application.yml

spring:
  datasource:
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
인텔리제이 같은 IDE, docker-compose는 이러한 .env 파일을 자동으로 읽어줄 수 있다.

 

2. 개발/운영 서버용으로 OS 환경변수를 설정하자.

# 윈도우 (cmd 기준)

set DB_USERNAME=junIsTheBestDev
set DB_PASSWORD=superSecret123!

# 리눅스/macOS

export DB_USERNAME=junIsTheBestDev
export DB_PASSWORD=superSecret123!
터미널에서 설정 후 실행해도 되고, 시스템 환경변수에 아예 등록해버릴 수도 있다. 환경변수를 시스템 전역/세션에 적용하는 이러한 방식은 주로 서버 배포, *CI/CD에서 사용한다. (*Continuous Integration, Continuous Delivery/Deployment)

 

▼ CI/CD에 대한 간략한 설명

더보기

CI/CD는 개발 → 테스트 → 배포 과정을 자동화해서 빠르고 안정적으로 소프트웨어를 만드는 방법이다.

(아래는 단순 예시다.)

  • 코드 푸시 → 자동으로 빌드 및 테스트
  • 테스트 성공 → 자동으로 스테이징 서버에 배포(Delivery)
  • 필요 시 자동으로 실제 운영 서버에 배포(Deployment)

마치며

말이 길었는데, 개발을 처음하는(나 같은) 비전공자들은 잘 이해되지 않을 수 있다.

 

그들을 위해 요약하자면,

스프링 부트는 애플리케이션 개발을 돕는 일종의 프레임워크인데, 그 안에서 JPA가 객체와 DB(데이터베이스)를 연결(매핑)하도록 한다. 여기서 우리는 DBMS로 MySQL을 선택했을 뿐인 거고, 그 MySQL은 도커를 통해 로컬에서 실행되는 컨테이너 환경에 띄운 것이다.