📘 Spring Boot JPA 정리 — 도서 CRUD 예제 기반
🧠 0️⃣ JPA란 무엇인가?
| 항목 | 설명 |
|---|
| 정의 | Java 진영의 ORM(Object Relational Mapping) 표준 명세 (API) |
| 풀네임 | Java Persistence API |
| 역할 | 자바 객체(클래스)와 관계형 데이터베이스의 테이블을 자동으로 매핑해주는 인터페이스 |
| 핵심 구현체 | Hibernate, EclipseLink, TopLink 등 |
| Spring Boot에서의 사용 | spring-boot-starter-data-jpa 의존성 추가 시 Hibernate 자동 사용 |
✅ 요약하자면
JPA = ORM의 표준 명세,
Hibernate = JPA의 대표 구현체
⚙️ JPA의 주요 특징
| 특징 | 설명 |
|---|
| 객체 중심 설계 | SQL 대신 Entity(객체)를 직접 다룸 |
| SQL 자동 생성 | save(), findAll() 등 CRUD 시 SQL 자동 실행 |
| 트랜잭션 관리 통합 | @Transactional 기반 자동 Commit/Rollback |
| 캐싱 기능 | 동일 트랜잭션 내 동일 Entity는 1차 캐시에 보관되어 중복 쿼리 방지 |
| 변경 감지 (Dirty Checking) | Entity의 필드 값이 변경되면 JPA가 자동으로 UPDATE SQL 수행 |
| 데이터베이스 독립성 | DBMS(MySQL, Oracle 등) 변경 시에도 코드 수정 최소화 |
🔄 JPA의 동작 구조
[1] EntityManagerFactory 생성
↓
[2] EntityManager (트랜잭션 단위)
↓
[3] EntityManager가 Entity를 영속성 컨텍스트에 저장
↓
[4] EntityManager.flush() → SQL 생성 및 DB 반영
↓
[5] Commit / Rollback 처리
| 단계 | 설명 |
|---|
| EntityManagerFactory | JPA의 핵심 매니저를 생성하는 팩토리 객체 (애플리케이션 전역 1개) |
| EntityManager | 실제 CRUD 작업 담당 (트랜잭션 단위로 생성) |
| 영속성 컨텍스트 (Persistence Context) | Entity 객체를 1차 캐시 형태로 관리하며 변경 감지 수행 |
1️⃣ 데이터베이스 분류
| 구분 | 설명 | 예시 |
|---|
| SQL (관계형) | 스키마 기반, 정형 데이터 | MySQL, Oracle |
| NoSQL (비관계형) | Key-Value / Document 구조 | Redis, MongoDB |
2️⃣ JDBC → ORM 관련 수강 과정
| 시기 | 기술 | 특징 |
|---|
| 7~8월 | JDBC / DAO | 수동 SQL 작성, ResultSet 수작업 |
| 9~10월 | MyBatis | SQL 분리(XML/Annotation), 반자동 매핑 |
| 11월 | JPA (Hibernate 기반) | SQL 없이 Java 객체로 CRUD 수행 |
3️⃣ ORM (Object-Relational Mapping)
- 정의 : 객체지향 언어(Java)의 클래스와 DB의 테이블을 매핑하는 기술
- 목적 : SQL 작성 없이 객체 중심의 데이터 접근 제공
- 주요 구현체 : MyBatis, Hibernate, JPA 등
4️⃣ Hibernate vs JPA
| 항목 | Hibernate | JPA |
|---|
| 정의 | ORM 프레임워크 (구현체) | Java ORM의 표준 명세 (API) |
| 역할 | 실제 데이터베이스 처리 로직 담당 | Hibernate 등의 구현체가 따라야 할 인터페이스 |
| 설치 | spring-boot-starter-data-jpa 추가 시 자동 포함 | |
5️⃣ JPA 핵심 구성요소
| 구성요소 | 설명 |
|---|
| Entity | DB 테이블과 매핑되는 클래스 |
| Repository | CRUD를 담당하는 인터페이스 |
| Service | 비즈니스 로직 처리 계층 |
| Controller | REST API 요청/응답 처리 계층 |
6️⃣ Gradle & properties 설정
Gradle
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'mysql:mysql-connector-j'
application.properties
# JPA DDL 설정
# Entity 테이블 CUD
# [8-1] Entity 테이블 삭제 후 생성
# spring.jpa.hibernate.ddl-auto=create
# [8-2] Entity 테이블이 존재하면 수정 / 존재하지 않으면 생성
spring.jpa.hibernate.ddl-auto=update
# [8-3] Entity 테이블을 직접관리하기 위해, CRUD 기능을 부여하지 않음
# spring.jpa.hibernate.ddl-auto=none
# [8.4] JPA가 처리한 SQL 문을 console에 출력
spring.jpa.show-sql=true
# [8.5] console에 출력된 SQL을 줄바꿈 처리하여 가독성을 높임
spring.jpa.properties.hibernate.format_sql=true
7️⃣ Entity 클래스 (BookEntity.java)
@Entity
@Table(name = "book")
public class BookEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false, length = 100)
private String title;
@Column(length = 50)
private String author;
@Column(length = 100)
private String publisher;
public BookEntity() {}
public BookEntity(String title, String author, String publisher) {
this.title = title;
this.author = author;
this.publisher = publisher;
}
}
8️⃣ Repository 인터페이스 (BookRepository.java)
@Repository
public interface BookRepository extends JpaRepository<BookEntity, Integer> {
}
9️⃣ Service 클래스 (BookService.java)
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
public BookEntity createBook(BookEntity book) {
return bookRepository.save(book);
}
public List<BookEntity> getAllBooks() {
return bookRepository.findAll();
}
@Transactional
public BookEntity updateBook(Integer id, BookEntity newBook) {
BookEntity book = bookRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("해당 도서 없음"));
book.setTitle(newBook.getTitle());
book.setAuthor(newBook.getAuthor());
book.setPublisher(newBook.getPublisher());
return book;
}
public void deleteBook(Integer id) {
bookRepository.deleteById(id);
}
}
🔟 Controller 클래스 (BookController.java)
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/books")
public class BookController {
private final BookService bookService;
@PostMapping("/create")
public ResponseEntity<BookEntity> createBook(@RequestBody BookEntity book) {
return ResponseEntity.ok(bookService.createBook(book));
}
@GetMapping("/all")
public ResponseEntity<List<BookEntity>> getAllBooks() {
return ResponseEntity.ok(bookService.getAllBooks());
}
@PutMapping("/update/{id}")
public ResponseEntity<BookEntity> updateBook(@PathVariable Integer id, @RequestBody BookEntity newBook) {
return ResponseEntity.ok(bookService.updateBook(id, newBook));
}
@DeleteMapping("/delete/{id}")
public ResponseEntity<String> deleteBook(@PathVariable Integer id) {
bookService.deleteBook(id);
return ResponseEntity.ok("삭제 완료");
}
}
✅ 핵심 요약
| 항목 | 설명 |
|---|
| Entity | DB 테이블과 매핑된 클래스 |
| Repository | JPA가 CRUD 메서드 자동 제공 |
| Service | 트랜잭션 관리 및 비즈니스 로직 담당 |
| Controller | REST API 처리 계층 |
| @Transactional | 하나의 DB 트랜잭션 단위로 묶어 처리 |
| 장점 | SQL 작성 불필요, 객체 중심 데이터 접근 |
| 주의 | Controller에서는 DTO 사용, Entity 직접 노출 지양 |
📚 출처: Spring Boot JPA 공식 문서, Hibernate User Guide, 실습 예제(Book CRUD)