Spring Boot에서 JPA를 사용할 때 알아야 할 핵심 개념들을 정리합니다. EntityManager 자동 구성, @Transactional의 동작 원리, 영속성 컨텍스트와 트랜잭션의 생명주기, 그리고 트랜잭션 전파까지 다룹니다.
의존성 추가
// build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Hibernate 설정 (application.properties)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
ddl-auto 옵션 정리
| 옵션 | 설명 |
|---|---|
create | 기존 테이블 DROP 후 다시 CREATE |
| create-drop | create와 동일하나, 애플리케이션 종료 시 테이블 DROP |
| update | 변경된 부분만 반영 |
| validate | Entity와 테이블 매핑이 정상인지 확인만 수행 |
| none | 아무것도 하지 않음 |
‼️주의 : 운영 환경에서는
validate또는none을 사용하는 것이 안전.create,update등은 개발 환경에서만 사용할 것
@Entity
@Getter @Setter
@Table(name = "memo")
@NoArgsConstructor
public class Memo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false)
private String username;
@Column(name = "contents", nullable = false, length = 500)
private String contents;
}
핵심 annotation :
@Entity -> JPA가 관리하는 엔티티 클래스로 지정@Table -> 매핑할 DB 테이블명 지정@Id + @GenaratedValue -> 기본 키 및 자동 생성 전략 설정@Column -> 컬럼 매핑 및 제약조건 설정EntityManagerFactory와 EntityManager를 직접 생성해야 했지만, SpringBoot에서는 자동 생성application.properties에 DB 정보를 설정하면, 이를 기반으로 EntityManagerFactory가 자동 생성되고, @PersistenceContext를 통해 EntityManager를 주입받아 사용 가능@PersistenceContext
EntityManager em;
@Transactional을 클래스나 메서드에 붙이면, 해당 범위의 모든 DB연산이 하나의 트랜잭션으로 묶입니다.
commitrollback// ❌ @Transactional 없음 → 실패!
@Test
void test2() {
Memo memo = new Memo();
memo.setUsername("Tom");
memo.setContents("테스트");
em.persist(memo); // 영속성 컨텍스트가 유지되지 않아 오류 발생
}
@Transactional(readOnly = true)
@Transactional(readOnly = true) // 클래스 전체: 읽기 전용
public class SimpleJpaRepository<T, ID> {
@Transactional // 이 메서드만 readOnly = false로 덮어쓰기
public <S extends T> S save(S entity) { ... }
}
메서드의 선언된 @Transactional이 클래스 레벨의 설정을 오버라이드 할 수 있음
스프링 컨테이너 환경에서는 영속성 컨텍스트와 트랜잭션의 생명주기가 일치합니다.
이것이 의미하는 바는 다음과 같습니다 :
앞선 test2()가 실패한 이유도 이와 같습니다. 트랜잭션이 없으므로 영속성 컨텍스트가 유지되지 않은 것입니다.
Service -> Repository 호출 시, 트랜잭션이 어떻게 이어지는 걸까요? Spring은 트랜잭션 전파 기능을 통해 이를 제어합니다.
@Transactional의 기본 전파 옵션은 REQUIRED입니다.
동작 확인
// 부모 메서드 (테스트)
@Test
@Transactional
@Rollback(value = false)
void test3() {
memoRepository.createMemo(em);
System.out.println("테스트 test3 메서드 종료");
}
// 자식 메서드 (Repository)
@Transactional
public Memo createMemo(EntityManager em) {
Memo memo = em.find(Memo.class, 1);
memo.setUsername("홍길동");
memo.setContents("@Transactional 전파 테스트 중!");
System.out.println("createMemo 메서드 종료");
return memo;
}
**부모 트랜잭션이 있는 경우:**
createMemo 메서드 종료
테스트 test3 메서드 종료
→ UPDATE 실행 (부모 메서드 종료 시점에 커밋)
**부모 트랜잭션이 없는 경우:**
createMemo 메서드 종료
→ UPDATE 실행 (자식 메서드 종료 시점에 자체 커밋)
테스트 test3 메서드 종료
| 개념 | 핵심 포인트 |
|---|---|
| Spring Boot JPA 설정 | starter-data-jpa의존성 + application.properties 설정으로 자동 구성 |
| EntityManager | @PersistenceContext로 자동 주입, 직접 생성 불필요 |
| @Transactional | CUD작업에 필수, 조회는 readOnly = true 권장 |
| 생명주기 | 트랜잭션 = 영속성 컨텍스트 생명주기 (스프링 컨테이너 환경) |
| 트랜잭션 전파 | 기본 REQUIRED - 부모 트랜잭션이 있으면 합류, 없으면 자체 생성 |