0. Spring Data JPA
- JPA (Java Persistence API): 자바의 표준 인터페이스로, 자바 객체를 DB에 저장할 때 따라야 하는 기본적인 규칙
- Hibernate: JPA를 실제로 구현한 라이브러리로, 실제 DB와 통신하고 SQL을 만드는 '엔진' 역할을 함.
- Spring Data JPA: Hibernate를 더 편하게 쓰기 위해 스프링이 한 번 더 감싸놓은 모듈이라고 함. 레포지토리 인터페이스만 만들면 구현체를 자동으로 생성해 준대요.
+) HikariCP
- Spring Boot가 기본적으로 내장하고 있는 라이브러리로, 얘가 JDBC Connection Pool 역할을 하는데, 미리 DB 연결 객체를 여러 개 만들어두고 빌려주는 방식이라 성능이 매우 빠르고 안정적이라고 한다.
+) JpaRepository를 상속받으면 기본 CRUD 외에도 메서드 이름만 잘 지으면 쿼리를 자동으로 만들어주는 쿼리 메서드 기능을 사용할 수 있다고 한다.
- 영속성 컨택스트 : 쉽게 말해 엔티티를 영구 저장하는 환경이라는 뜻으로, 정확히는 애플리케이션과 DB 사이에 있는 중간 저장소(1차 캐시)라고 함. JPA는 데이터를 DB에 바로 넣지 않고, 잠시 이 중간 저장소에 보관해서 나중에 ID가 1인 User를 조회할 때, 여기에 있다면 DB에 쿼리를 보내지 않고 그냥 가져올 수 있어 성능이 향상됨! 쓰기 지연 기능도 있다고 함.
1. DB 및 프로젝트 준비

- ID : stdUser / PW : wkvmtlf2 / DB명 : Test_SpringDB 로 MariaDB를 준비했다.

- 프로젝트명 : SpringBootDB
- Spring Data JPA: DB 처리를 위한 핵심 라이브러리
- MySQL/MariaDB Driver: DB와 연결하기 위한 드라이버
- Spring Web: 웹 MVC 패턴 구현을 위해 필요
- application.properties에 ID와 PW, 그리고 DB명을 입력해주었다.
spring.application.name=SpringBootDB
spring.datasource.hikari.jdbc-url=jdbc:mariadb://localhost:3306/Test_SpringDB
spring.datasource.hikari.username=stdUser
spring.datasource.hikari.password=wkvmtlf2
spring.datasource.hikari.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.show-sql=true
2. Entity 클래스 생성 (User.java)
- DB의 테이블과 1:1로 매핑되는 User 클래스를 생성함
package kr.ac.ewha.java2.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity //이 클래스가 DB 테이블과 매핑됨을 명시
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
- JPA는 기본 생성자가 필수다. 그 외에 데이터 삽입용(ID 제외), 수정/조회용(전체 필드) 생성자도 함께 만들어두면 편리하다고 한다..
3. Repository 생성 (UserRepository.java)
- DAO를 만들고 SQL을 직접 짤 필요 없이 Spring Data JPA에서는 인터페이스 하나면 구현이 가능함.
- JpaRepository<User, Integer>를 상속받는 인터페이스를 생성하면 여러 메서드가 자동 생성되어 바로 사용이 가능.
package kr.ac.ewha.java2.repository;
import org.springframework.data.jpa.repository.*;
import org.springframework.stereotype.Repository;
import kr.ac.ewha.java2.entity.User;
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}
4. 서비스(Service) 구현 (UserService.java)
- 비즈니스 로직을 담당하는 서비스 클래스로, 컨트롤러와 리포지토리 사이에서 다리 역할을 함.
- UserRepository를 주입받아 CRUD 기능을 구현함.
// 수업시간 보충용 서비스 클래스
package kr.ac.ewha.java2.service;
import java.util.List;
import org.springframework.stereotype.Service;
import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.repository.UserRepository;
@Service // 이 클래스가 Spring의 서비스 컴포넌트임을 나타냄 (비즈니스 로직 담당)
public class UserService {
// UserRepository를 주입받기 위한 필드 (데이터베이스 접근을 위한 인터페이스)
private final UserRepository repository;
// 생성자를 통한 의존성 주입 (Spring이 자동으로 주입해줌)
public UserService(UserRepository repository) {
this.repository = repository;
}
// CREATE: 새로운 사용자 생성 및 저장 (repository.save())
public User create(User user) {
return repository.save(user); // JPA의 save() 메서드를 통해 DB에 저장
}
// READ: 모든 사용자 목록 조회 (repository.findAll())
public List<User> read() {
return repository.findAll(); // 모든 사용자 엔티티를 리스트로 반환
}
// READ: ID로 사용자 조회 (없으면 null 반환) (repository.findById())
public User readById(int id) {
return repository.findById(id).orElse(null); // Optional에서 값이 없으면 null 반환
}
// UPDATE: ID로 사용자 조회 후 이름과 나이를 수정 (save())
public User update(int id, User updatedUser) {
User user = readById(id); // 기존 사용자 조회
if (user == null) {
return null; // 사용자가 없으면 null 반환
}
// 사용자 정보 업데이트
user.setName(updatedUser.getName());
user.setAge(updatedUser.getAge());
return repository.save(user); // 수정된 사용자 저장
}
// DELETE: ID로 사용자 삭제 (성공 여부를 Boolean으로 반환) (repository.deleteById())
public Boolean delete(int id) {
if (!repository.existsById(id)) {
return false; // 사용자가 없으면 false 반환
}
repository.deleteById(id); // 사용자 삭제
return true; // 삭제 성공 시 true 반환
}
}
5. 컨트롤러(Controller) 구현 (`SpringDBController.java`)
- 사용자의 요청(URL)을 받아 적절한 서비스를 호출하고 결과를 반환하는 컨트롤러
- 여기선 간단하게 HTML 문자열을 직접 리턴하거나 폼 데이터를 처리하는 방식을 사용한다고 함.
// 사용자 관련 요청을 처리하는 Spring MVC 컨트롤러 클래스
package kr.ac.ewha.java2.controller;
import org.springframework.web.bind.annotation.*;
import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.service.UserService;
import org.springframework.stereotype.Controller;
import java.util.List;
@Controller // 이 클래스가 Spring의 컨트롤러임을 나타냄
@RequestMapping("/user") // 모든 요청 경로 앞에 "/user"를 붙임
public class SpringDBController {
// 사용자 관련 비즈니스 로직을 처리하는 서비스 객체
private final UserService service;
// 생성자를 통해 UserService를 주입받음
public SpringDBController(UserService service) {
this.service = service;
}
// CREATE: 사용자 등록 처리
@PostMapping("/submitForm") // POST 요청 "/user/submitForm" 처리
@ResponseBody // 반환값을 HTTP 응답 본문으로 직접 출력
public String create(@RequestParam("name") String name, @RequestParam("age") int age) {
service.create(new User(name, age)); // 사용자 생성 및 저장
return "<h3>등록 완료</h3><a href='/user-crud.html'>돌아가기</a>"; // 결과 HTML 반환
}
// READ: ID로 사용자 조회
@GetMapping // GET 요청 "/user?id=..." 처리
@ResponseBody
public String readById(@RequestParam("id") int id) {
User user = service.readById(id); // ID로 사용자 조회
if (user == null) return "사용자 없음!"; // 없으면 메시지 반환
// 사용자 정보 HTML로 반환
return "<h3>사용자 정보</h3>" +
"<p>ID: " + user.getId() + "</p>" +
"<p>이름: " + user.getName() + "</p>" +
"<p>나이: " + user.getAge() + "</p>" +
"<a href='/user-crud.html'>돌아가기</a>";
}
// READ: 전체 사용자 목록 조회
@GetMapping("/list") // GET 요청 "/user/list" 처리
@ResponseBody
public String list() {
List<User> users = service.read(); // 모든 사용자 조회
// HTML 테이블로 사용자 목록 구성
StringBuilder html = new StringBuilder("<h3>전체 사용자 목록</h3><table border='1'><tr><th>ID</th><th>이름</th><th>나이</th></tr>");
for (User u : users) {
html.append("<tr><td>").append(u.getId()).append("</td><td>")
.append(u.getName()).append("</td><td>")
.append(u.getAge()).append("</td></tr>");
}
html.append("</table><br><a href='/user-crud.html'>돌아가기</a>");
return html.toString(); // HTML 반환
}
// UPDATE: 사용자 정보 수정
@PostMapping("/updateForm") // POST 요청 "/user/updateForm" 처리
@ResponseBody
public String update(@RequestParam("id") int id,
@RequestParam("name") String name,
@RequestParam("age") int age) {
User result = service.update(id, new User(name, age)); // 사용자 수정
if (result == null) {
return "<h3>수정 실패: 사용자를 찾을 수 없습니다.</h3><a href='/user-crud.html'>돌아가기</a>"; // 실패 시 메시지
}
return "<h3>수정 완료</h3><a href='/user-crud.html'>돌아가기</a>"; // 성공 시 메시지
}
// DELETE: 사용자 삭제
@PostMapping("/deleteForm") // POST 요청 "/user/deleteForm" 처리
@ResponseBody
public String delete(@RequestParam("id") int id) {
boolean success = service.delete(id); // 사용자 삭제
if (!success) {
return "<h3>삭제 실패: 사용자를 찾을 수 없습니다.</h3><a href='/user-crud.html'>돌아가기</a>"; // 실패 시 메시지
}
return "<h3>삭제 완료</h3><a href='/user/list'>전체 목록 보기</a>"; // 성공 시 메시지
}
}
- '/user/submitForm': 사용자 등록 (POST)
- '/user/list': 전체 목록 조회 (GET) - HTML 테이블 형태로 반환
- '/user': ID로 상세 조회 (GET)
- '/user/updateForm': 정보 수정 (POST)
- '/user/deleteForm': 삭제 (POST)
6. 웹페이지
- 입력을 받을 HTML 웹페이지를 생성하자!
1) input.html
<html>
<body>
<meta charset="UTF-8">
<form method="post" action="http://127.0.0.1:8080/user/submitForm" accept-charset="UTF-8">
<input type="text" name="name" value="이름" />
<input type="number" name="age" value="5" />
<button type="submit" >보내기</button>
</form>
</body>
</html>
2) user-crud.html
<!DOCTYPE html>
<html lang="ko"> <!-- 문서의 언어를 한국어로 설정 -->
<head>
<meta charset="UTF-8"> <!-- 문자 인코딩을 UTF-8로 설정 -->
<title>사용자 CRUD - action 방식</title> <!-- 브라우저 탭에 표시될 제목 -->
</head>
<body>
<h1>사용자 CRUD (action 방식)</h1> <!-- 페이지의 메인 제목 -->
<!-- CREATE: 사용자 등록 폼 -->
<h2>사용자 등록</h2>
<form method="post" action="/user/submitForm"> <!-- POST 방식으로 /user/submitForm에 데이터 전송 -->
이름: <input type="text" name="name" required /> <!-- 이름 입력 필드 (필수) -->
나이: <input type="number" name="age" required /> <!-- 나이 입력 필드 (필수) -->
<button type="submit">등록</button> <!-- 폼 제출 버튼 -->
</form>
<!-- READ (단일 조회): ID로 사용자 조회 -->
<h2>사용자 조회 (ID로)</h2>
<form method="get" action="/user"> <!-- GET 방식으로 /user에 ID 전송 -->
ID: <input type="number" name="id" required /> <!-- 조회할 사용자 ID 입력 -->
<button type="submit">조회</button> <!-- 조회 버튼 -->
</form>
<!-- READ (전체 조회): 모든 사용자 목록 조회 -->
<h2>전체 사용자 조회</h2>
<form method="get" action="/user/list"> <!-- GET 방식으로 /user/list 요청 -->
<button type="submit">전체 목록 보기</button> <!-- 전체 목록 보기 버튼 -->
</form>
<!-- UPDATE: 사용자 정보 수정 -->
<h2>사용자 수정</h2>
<form method="post" action="/user/updateForm"> <!-- POST 방식으로 /user/updateForm에 데이터 전송 -->
ID: <input type="number" name="id" required /> <!-- 수정할 사용자 ID 입력 -->
새 이름: <input type="text" name="name" required /> <!-- 새 이름 입력 -->
새 나이: <input type="number" name="age" required /> <!-- 새 나이 입력 -->
<button type="submit">수정</button> <!-- 수정 버튼 -->
</form>
<!-- DELETE: 사용자 삭제 -->
<h2>사용자 삭제</h2>
<form method="post" action="/user/deleteForm"> <!-- POST 방식으로 /user/deleteForm에 ID 전송 -->
ID: <input type="number" name="id" required /> <!-- 삭제할 사용자 ID 입력 -->
<button type="submit">삭제</button> <!-- 삭제 버튼 -->
</form>
</body>
</html>
- 아직 잘 모르지만 JavaScript나 Thymeleaf 같은 템플릿 엔진을 쓰면 더 편하다고는 한다..
7. 실행 및 테스트 (SpringBootDbApplication.java)
- 메인 어플리케이션 파일.
package kr.ac.ewha.java2;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.service.UserService;
@SpringBootApplication
public class SpringBootDbApplication implements CommandLineRunner {
@Autowired
private UserService userService;
public static void main(String[] args) {
SpringApplication.run(SpringBootDbApplication.class, args);
System.out.println("Project : Spring Boot DB start!");
}
@Override //코드에서 테스트하기
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
System.out.println("Spring DB is running");
List <User> users = userService.read();
//DB내용 불럭오기
for (User u : users) {
System.out.println(u.getId() + u.getName());
}
//코드에서 추가하기
//userService.create(new User("까만둥이",10));
//User user =new User();
//user.setName("유리유리");
//user.setAge(5);
//userService.create(user);
}
}
8. 실행 결과
- 삽입도 잘 되는데 전체 사용자 조회는 왜 안 되는지 모르겠다... Error가 나서 뜨질 않는다ㅠ


9. 소감
원래는 UserDAO 클래스를 만들고 무언가를 막 짜야 했었는데 Spring을 사용하니 UserRepository 하나만 만들어놓으면 이 내부구현을 알아서 다 해주는 게 신기했다... 또 JPA를 사용하니 application.properties에 어떤 DB에 연결하고 ID가 뭐고 PW가 뭐고를 다 적어놓으면 되니까 JDBC를 쓸 때와는 달리 Connection 객체를 관리하지 않아도 되어서 편했다.. Spring이 정말 편리하다는 걸 그 전에 실습을 해보지 않았다면 몰랐을 것 같다... 문법이 익숙칠 않아 자꾸 뭔가를 타이핑하는 걸 까먹긴 했지만 그래도 획기적이네요. 익숙해지면 좋을 것 같다!
'Develop > Java' 카테고리의 다른 글
| [프로젝트] 마피아 게임 프로젝트 후기 (0) | 2025.12.03 |
|---|---|
| [10주차] SpringBoot - 1 (0) | 2025.11.23 |
| [9주차] DB & JDBC (0) | 2025.11.16 |
| [8주차] GUI + Event + Thread를 이용한 망나니 잡기 (0) | 2025.11.02 |
| [7주차-2] 디자인패턴 추가조사 - 데코레이터 패턴 (0) | 2025.10.18 |