이전 글에서는 DB에 들어가기 전에 Repository가 왜 필요한지 정리했습니다.
그때는 회원 정보를 ArrayList에 저장했습니다.
private final List<Member> members = new ArrayList<>();
이 방식은 흐름을 이해하기에는 좋지만, 서버를 끄면 데이터가 사라집니다.
이번 글에서는 한 단계 더 나아가서 진짜 데이터베이스에 회원을 저장해보겠습니다.
처음부터 MySQL로 가면 설정이 조금 부담될 수 있으니, 이번 글에서는 먼저 H2 데이터베이스를 사용합니다.
H2는 가볍게 실행할 수 있는 학습용 DB라서 Spring Boot 입문 단계에서 많이 사용합니다.
이번 글의 목표는 딱 하나입니다.
진짜 DB에 데이터를 저장해보기
오늘 만들 기능
이번 글에서는 아래 흐름을 만들어보겠습니다.
- H2 데이터베이스 연결
- JDBC URL 설정
members테이블 생성- 회원 이름 저장
- 저장된 회원 목록 조회
아직 JPA는 사용하지 않습니다.
이번 글에서는 DB 연결 흐름을 더 잘 보기 위해 JdbcTemplate을 사용하겠습니다.
전체 흐름 먼저 보기
회원 저장 흐름은 이렇게 이어집니다.
브라우저 요청
↓
Controller
↓
Service
↓
Repository
↓
H2 Database
이전에는 Repository가 ArrayList에 저장했습니다.
이번에는 Repository가 DB에 SQL을 보내서 저장합니다.
즉, Repository의 저장 대상이 바뀝니다.
이전: Repository → ArrayList
이번: Repository → H2 Database
1. 필요한 의존성 추가하기
Spring Initializr에서 프로젝트를 만들 때 아래 의존성을 추가하면 됩니다.
- Spring Web
- JDBC API
- H2 Database
이미 프로젝트가 있다면 build.gradle에 아래 의존성이 있는지 확인합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
}
각각의 역할은 이렇습니다.
| 의존성 | 역할 |
|---|---|
spring-boot-starter-web | 웹 요청 처리 |
spring-boot-starter-jdbc | JDBC로 DB 접근 |
h2 | H2 데이터베이스 사용 |
처음에는 이름이 길어 보여도 이렇게만 이해하면 됩니다.
web = 웹 기능
jdbc = DB 연결 기능
h2 = 사용할 DB
2. H2 DB 설정하기
DB 설정은 보통 application.properties 파일에 작성합니다.
파일 위치는 아래와 같습니다.
src/main/resources/application.properties
아래 설정을 추가합니다.
spring.datasource.url=jdbc:h2:file:./data/demo-db
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.sql.init.mode=always
설정 하나씩 보기
1. JDBC URL
spring.datasource.url=jdbc:h2:file:./data/demo-db
이 설정은 어떤 DB에 연결할지 알려주는 주소입니다.
여기서 중요한 부분은 jdbc:h2:file:./data/demo-db입니다.
쉽게 말하면:
H2 데이터베이스를 파일 형태로 사용하고,
프로젝트 안의 data/demo-db 위치에 저장하겠다.
이렇게 파일 방식으로 설정하면 서버를 껐다 켜도 데이터가 남아 있을 수 있습니다.
2. Driver 설정
spring.datasource.driver-class-name=org.h2.Driver
Driver는 Java가 DB와 대화할 수 있게 도와주는 연결 도구입니다.
처음에는 이렇게 이해하면 됩니다.
Driver = Java와 DB 사이의 통역사
3. DB 사용자 이름과 비밀번호
spring.datasource.username=sa
spring.datasource.password=
H2에서는 학습용으로 sa 사용자를 자주 사용합니다.
비밀번호는 비워두었습니다.
4. H2 콘솔 켜기
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
이 설정을 하면 브라우저에서 H2 DB 화면에 접속할 수 있습니다.
Spring Boot를 실행한 뒤 아래 주소로 접속합니다.
http://localhost:8080/h2-console
콘솔 화면에서 JDBC URL에 아래 값을 입력합니다.
jdbc:h2:file:./data/demo-db
사용자 이름은 sa입니다.
3. 테이블 생성하기
DB에 데이터를 저장하려면 먼저 테이블이 필요합니다.
회원 정보를 저장할 members 테이블을 만들어보겠습니다.
아래 파일을 생성합니다.
src/main/resources/schema.sql
그리고 아래 SQL을 작성합니다.
CREATE TABLE IF NOT EXISTS members (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
테이블이란?
테이블은 데이터를 저장하는 표입니다.
이번 예제에서는 회원 정보를 저장하기 위해 members 테이블을 만듭니다.
| 컬럼 | 의미 |
|---|---|
id | 회원 번호 |
name | 회원 이름 |
즉, 회원 한 명이 저장되면 DB에는 이런 식으로 들어갑니다.
| id | name |
|---|---|
| 1 | kim |
| 2 | park |
SQL 코드 설명
CREATE TABLE IF NOT EXISTS members
members 테이블이 없으면 새로 만들겠다는 뜻입니다.
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
id는 회원을 구분하는 번호입니다.
GENERATED BY DEFAULT AS IDENTITY는 값을 직접 넣지 않아도 DB가 번호를 자동으로 만들어준다는 뜻입니다.
name VARCHAR(255) NOT NULL
name은 회원 이름입니다.
NOT NULL은 이름이 비어 있으면 안 된다는 뜻입니다.
4. Member 객체 만들기
회원 정보를 담을 Member 클래스를 만듭니다.
src/main/java/com/example/demo/Member.java
package com.example.demo;
public class Member {
private Long id;
private String name;
public Member(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
이 클래스는 DB에서 가져온 회원 정보를 Java 코드에서 다루기 위한 객체입니다.
5. Repository 만들기
이제 DB에 회원을 저장하고 조회하는 Repository를 만듭니다.
src/main/java/com/example/demo/MemberRepository.java
package com.example.demo;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.List;
@Repository
public class MemberRepository {
private final JdbcTemplate jdbcTemplate;
public MemberRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public Member save(String name) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO members(name) VALUES (?)",
Statement.RETURN_GENERATED_KEYS
);
ps.setString(1, name);
return ps;
}, keyHolder);
Long id = keyHolder.getKey().longValue();
return new Member(id, name);
}
public List<Member> findAll() {
return jdbcTemplate.query(
"SELECT id, name FROM members ORDER BY id",
(rs, rowNum) -> new Member(
rs.getLong("id"),
rs.getString("name")
)
);
}
}
Repository 코드 설명
1. JdbcTemplate 사용하기
private final JdbcTemplate jdbcTemplate;
JdbcTemplate은 SQL을 더 편하게 실행할 수 있도록 도와주는 Spring 도구입니다.
직접 DB 연결 코드를 길게 작성하지 않아도, SQL을 실행할 수 있게 도와줍니다.
처음에는 이렇게 이해하면 됩니다.
JdbcTemplate = SQL을 DB에 보내주는 도구
2. 회원 저장하기
"INSERT INTO members(name) VALUES (?)"
이 SQL은 members 테이블에 회원 이름을 저장합니다.
?는 나중에 들어갈 값을 의미합니다.
아래 코드에서 그 자리에 name 값을 넣습니다.
ps.setString(1, name);
예를 들어 name이 kim이면 실제로는 이런 느낌입니다.
INSERT INTO members(name) VALUES ('kim');
3. 자동 생성된 id 받기
Statement.RETURN_GENERATED_KEYS
DB가 자동으로 만든 id 값을 다시 받기 위한 설정입니다.
회원을 저장하면 DB가 id를 만들어줍니다.
그 값을 받아서 Member 객체로 반환합니다.
Long id = keyHolder.getKey().longValue();
return new Member(id, name);
4. 회원 목록 조회하기
"SELECT id, name FROM members ORDER BY id"
이 SQL은 members 테이블에 저장된 회원 목록을 조회합니다.
ORDER BY id는 id 순서대로 정렬하겠다는 뜻입니다.
조회 결과는 아래 코드에서 Member 객체로 바뀝니다.
(rs, rowNum) -> new Member(
rs.getLong("id"),
rs.getString("name")
)
6. Service 만들기
회원 등록 규칙을 처리할 Service를 만듭니다.
src/main/java/com/example/demo/MemberService.java
package com.example.demo;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public Member join(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("이름은 비어 있을 수 없습니다.");
}
return memberRepository.save(name);
}
public List<Member> findMembers() {
return memberRepository.findAll();
}
}
Service는 이름이 비어 있는지 확인하고, 문제가 없으면 Repository에 저장을 맡깁니다.
7. Controller 만들기
브라우저 요청을 받을 Controller를 만듭니다.
src/main/java/com/example/demo/MemberController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class MemberController {
private final MemberService memberService;
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@GetMapping("/members/new")
public Member join(@RequestParam("name") String name) {
return memberService.join(name);
}
@GetMapping("/members")
public List<Member> members() {
return memberService.findMembers();
}
}
8. 실행해보기
Spring Boot를 실행합니다.
Gradle 프로젝트라면 아래 명령어를 사용할 수 있습니다.
./gradlew bootRun
서버가 실행되면 브라우저에서 아래 주소로 접속합니다.
http://localhost:8080/members/new?name=kim
결과는 대략 이렇게 나옵니다.
{
"id": 1,
"name": "kim"
}
이번에는 다른 회원도 등록해봅니다.
http://localhost:8080/members/new?name=park
결과는 대략 이렇게 나옵니다.
{
"id": 2,
"name": "park"
}
이제 저장된 회원 목록을 조회합니다.
http://localhost:8080/members
결과는 이렇게 나올 수 있습니다.
[
{
"id": 1,
"name": "kim"
},
{
"id": 2,
"name": "park"
}
]
이제 회원 정보가 메모리 리스트가 아니라 H2 DB에 저장됩니다.
9. H2 콘솔에서 직접 확인하기
브라우저에서 아래 주소로 접속합니다.
http://localhost:8080/h2-console
접속 화면에서 JDBC URL에 아래 값을 입력합니다.
jdbc:h2:file:./data/demo-db
사용자 이름은 다음과 같이 입력합니다.
sa
비밀번호는 비워둡니다.
접속한 뒤 아래 SQL을 실행해봅니다.
SELECT * FROM members;
그러면 브라우저로 등록한 회원 데이터가 DB에 들어간 것을 확인할 수 있습니다.
JDBC URL이란?
JDBC URL은 Java가 어떤 DB에 연결할지 알려주는 주소입니다.
이번 글에서는 아래 값을 사용했습니다.
jdbc:h2:file:./data/demo-db
이 값을 나눠보면 이런 의미입니다.
| 부분 | 의미 |
|---|---|
jdbc | Java에서 DB에 연결할 때 사용하는 방식 |
h2 | H2 데이터베이스 사용 |
file | 파일 형태로 저장 |
./data/demo-db | DB 파일 위치 |
처음에는 이렇게 기억하면 됩니다.
JDBC URL = Java가 DB를 찾기 위한 주소
메모리 저장소와 DB 저장소 비교
이전 글에서는 ArrayList에 저장했습니다.
이번 글에서는 H2 DB에 저장했습니다.
차이는 다음과 같습니다.
| 구분 | 메모리 저장소 | H2 DB |
|---|---|---|
| 저장 위치 | Java 프로그램 메모리 | 데이터베이스 파일 |
| 서버 재시작 후 데이터 | 사라짐 | 남아 있을 수 있음 |
| SQL 사용 | 사용 안 함 | 사용함 |
| 실제 DB 흐름 연습 | 약함 | 가능 |
H2도 학습용으로 가볍게 쓰는 DB지만, SQL로 테이블을 만들고 데이터를 저장하는 흐름을 경험할 수 있습니다.
MySQL을 쓰고 싶다면?
처음에는 H2로 연습하는 것을 추천합니다.
그래도 MySQL을 사용하고 싶다면 설정은 대략 이렇게 바뀝니다.
먼저 MySQL 데이터베이스를 만들어야 합니다.
CREATE DATABASE demo_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
그리고 application.properties는 아래처럼 설정할 수 있습니다.
spring.datasource.url=jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=본인비밀번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
그리고 build.gradle에는 MySQL 드라이버가 필요합니다.
runtimeOnly 'com.mysql:mysql-connector-j'
MySQL에서는 테이블 생성 SQL을 이렇게 작성할 수 있습니다.
CREATE TABLE members (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
하지만 처음에는 DB 설치와 계정 설정에서 막힐 수 있으니, 이번 단계에서는 H2로 먼저 흐름을 잡는 것이 좋습니다.
자주 헷갈리는 부분
1. H2도 DB인가?
네, H2도 데이터베이스입니다.
다만 가볍고 설정이 쉬워서 학습용으로 많이 사용합니다.
실제 서비스에서는 MySQL, PostgreSQL 같은 DB를 더 많이 사용합니다.
2. JDBC URL을 왜 맞춰야 할까?
Spring Boot 설정에 적은 JDBC URL과 H2 콘솔에서 접속할 때 입력하는 JDBC URL이 같아야 같은 DB를 봅니다.
예를 들어 설정에는 아래처럼 적었는데
jdbc:h2:file:./data/demo-db
H2 콘솔에서는 다른 값을 입력하면 다른 DB에 접속할 수 있습니다.
그러면 저장한 데이터가 안 보일 수 있습니다.
3. schema.sql은 언제 실행될까?
schema.sql은 애플리케이션이 시작될 때 실행될 수 있습니다.
이번 글에서는 아래 설정을 추가했습니다.
spring.sql.init.mode=always
그래서 서버가 시작될 때 schema.sql을 실행해 테이블을 준비합니다.
4. GET으로 저장해도 괜찮을까?
이번 글에서는 초보자가 브라우저 주소창으로 쉽게 테스트할 수 있도록 GET 요청으로 회원을 저장했습니다.
/members/new?name=kim
하지만 실제 서비스에서는 데이터를 저장할 때 보통 POST 요청을 사용합니다.
즉, 이번 방식은 학습용입니다.
나중에 API를 제대로 만들 때는 @PostMapping을 사용해서 저장 기능을 만드는 것이 더 적절합니다.
오늘 배운 것
이번 글에서는 Spring Boot에서 H2 DB를 연결하고 회원을 저장해봤습니다.
핵심은 아래와 같습니다.
- DB 설정은
application.properties에 작성함 - JDBC URL은 Java가 DB를 찾기 위한 주소임
schema.sql로 테이블을 만들 수 있음- Repository에서
JdbcTemplate으로 SQL을 실행할 수 있음 INSERT로 회원을 저장하고SELECT로 회원 목록을 조회할 수 있음- H2 콘솔에서 실제 저장된 데이터를 확인할 수 있음
정리
이번 글에서는 메모리 저장소를 벗어나 실제 DB에 데이터를 저장해봤습니다.
이전에는 회원이 ArrayList에 저장됐습니다.
이번에는 회원이 H2 데이터베이스의 members 테이블에 저장됩니다.
흐름은 이렇게 바뀌었습니다.
이전: Controller → Service → Repository → ArrayList
이번: Controller → Service → Repository → H2 Database
처음에는 DB 설정, JDBC URL, SQL이 낯설 수 있습니다.
하지만 핵심은 단순합니다.
DB에 연결하고,
테이블을 만들고,
SQL로 데이터를 저장한다.
이 흐름을 이해하면 다음 단계인 JPA를 배울 때 훨씬 덜 헷갈립니다.
다음 글에서는 JPA를 사용해서 SQL을 직접 많이 작성하지 않고 저장과 조회를 처리하는 방법을 정리해보겠습니다.