📙 목차
1. Spring Boot와 JPA
Spring Boot는 JPA 설정을 자동으로 구성하여 JPA를 쉽게 사용할 수 있도록 도와준다.
기존 코드
- 직접 트랜잭션을 사용한다.(JPA는 기본적으로 하나의 트랜잭션 안에서 기능을 수행한다)
- 직접 EntityManagerFactory 와 EntityManager 를 생성하여 사용한다.
- 직접 close() 하여 연결을 종료 해야한다.
public static void main(String[] args) {
// EntityManagerFactory 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
// EntityManager 생성
EntityManager em = emf.createEntityManager();
// Transaction 생성
EntityTransaction transaction = em.getTransaction();
// 트랜잭션 시작
transaction.begin();
try {
// 비영속
Tutor tutor = new Tutor(1L, "wonuk", 100);
System.out.println("persist 전");
// 영속
em.persist(tutor);
System.out.println("persist 후");
// transaction이 commit되며 실제 SQL이 실행된다.
transaction.commit();
} catch (Exception e) {
// 실패 -> 롤백
e.printStackTrace();
transaction.rollback();
} finally {
// 엔티티 매니저 연결 종료
em.close();
}
emf.close();
}
Spring Boot와 JPA
- JPA는 Spring에 종속적인 것이 아니다.
- Spring Boot 에서 JPA를 사용하기 위해서는 build.gradle에 의존성 추가가 필요하다.
- spring-boot-starter-data-jpa
- 필요한 JPA 설정과 Entity 관리를 자동으로 해준다.
- 자동으로 내부에서 EntityManagerFactory 를 하나만 생성해서 관리(싱글톤)한다.
- 자동으로 Bean으로 등록된다.
- 직접 만들지 않아도 된다.
- 직접 연결을 close() 하지 않아도 된다.
- application.properties 에 설정된 DB 정보로 생성된다.
- @PersistenceContext를 통해 자동으로 생성된 EntityManager를 주입받아 사용할 수 있다.
@Repository
public class TutorRepository {
@PersistenceContext
private EntityManager em;
public void save(Tutor tutor) {
em.persist(tutor);
}
public Tutor findById(Long id) {
return em.find(Tutor.class, id);
}
public List<Tutor> findAll() {
return em.createQuery("SELECT * FROM tutor", Tutor.class).getResultList();
}
public void delete(Tutor tutor) {
em.remove(tutor);
}
}
2. Spring Data JPA
Spring Data JPA
- Spring Framework에서 JPA를 쉽게 사용할 수 있도록 제공하는 모듈
Spring Data JPA 특징
- JPA 추상화 Repository 제공
- CrudRepository, JpaRepository 인터페이스를 제공한다.
- SQL이나 EntityManager를 직접 호출하지 않아도 기본적인 CRUD 기능을 손쉽게 구현할 수 있다.
- JPA 구현체와 통합
- 일반적으로 Hibernate를 통해 자동으로 SQL이 생성된다.
- QueryMethods
- Method 이름만으로 SQL을 자동으로 생성한다.
- @Query 를 사용하여 JPQL 또는 Native Query를 정의할 수 있다.
- 복잡한 SQL을 직접 구현할 때 사용
- 트랜잭션 관리와 LazyLoading
- 트랜잭션 기능을 Spring과 통합하여 제공한다.
- 연관된 Entity를 필요할 때 로딩하는 지연로딩 기능을 지원한다.
기존 JPA 방식
- 반복되는 CRUD 코드가 많다.
public class MemberRepository {
@PersistenceContext
private EntityManager em;
public void save(Member member) {
em.persist(member);
}
public Member findById(Long id) {
return em.find(Member.class, id);
}
public List<Member> findAll() {
return em.createQuery("SELECT * FROM member", Member.class).getResultList();
}
public void delete(Member member) {
em.remove(member);
}
}
Spring Data JPA 방식
- JpaRepository 상속만으로 CRUD 메서드를 모두 사용할 수 있다.
- 반복되는 코드가 제거되고 생산성이 높아진다.
public interface MemberRepository extends JpaRepository<Member, Long> {
Member findById(Long id);
}
3. SimpleJpaRepository
SimpleJpaRepository
- Spring Data JPA에서 JpaRepository 인터페이스의 기본 구현체
- JpaRepository를 상속하면, Spring이 내부적으로 이 SimpleJpaRepository 클래스를 사용해 실제 동작을 수행한다.
- 기본 CRUD 기능을 구현해 놓은 클래스로, 직접 구현하지 않아도 JpaRepository만 상속하면 CRUD 기능이 자동 제공된다.
4. Query Methods
Query Methods
- Spring Data JPA에서 메서드 이름을 기반으로 데이터베이스 쿼리를 자동 생성하는 기능
- 직접 SQL을 작성하지 않고도 복잡한 쿼리를 쉽게 수행할 수 있게 된다
기본 문법
findBy | readBy | getBy | queryBy | countBy | deleteBy | removeBy + 조건절
예제
public interface UserRepository extends JpaRepository<User, Long> {
// 이름으로 조회
List<User> findByName(String name);
// 나이가 특정 값보다 큰 사용자 조회
List<User> findByAgeGreaterThan(int age);
// 이메일이 null이 아닌 사용자 조회
List<User> findByEmailIsNotNull();
// 이름과 나이 모두 조건으로 조회
List<User> findByNameAndAge(String name, int age);
// 이름 또는 이메일 조건으로 조회
List<User> findByNameOrEmail(String name, String email);
// 이름에 특정 문자열 포함하는 사용자 조회 (like '%str%')
List<User> findByNameContaining(String keyword);
// 정렬과 페이징 지원 가능
Page<User> findByAgeGreaterThanOrderByAgeDesc(int age, Pageable pageable);
}
주요 키워드
키워드 | 의미 |
And | 조건 AND 결합 |
Or | 조건 OR 결합 |
Is, Equals | 같다 (기본 조건) |
Between | 범위 (>=, <=) |
LessThan | 작다 (<) |
GreaterThan | 크다 (>) |
Like | LIKE 연산 |
StartingWith | 시작하는 문자열 조회 |
EndingWith | 끝나는 문자열 조회 |
Containing | 포함하는 문자열 조회 |
OrderBy | 정렬 |
IsNull, IsNotNull | NULL 여부 체크 |
장단점
장점 | 단점 |
간단한 조건 조회는 빠르고 편리하다 | 복잡한 쿼리는 메서드 이름이 너무 길어진다 |
가독성이 좋다 | 이름으로 표현하기 어려운 쿼리도 있다 |
별도 쿼리 작성이 필요 없다 | 성능 튜닝을 위한 세밀한 제어가 어렵다 |
* Query Methods는 간단하고 반복적인 조회 쿼리를 빠르게 구현할 때 최적이다
* 복잡하거나 최적화가 필요한 쿼리는 @Query 어노테이션이나 Querydsl을 함께 사용하는 것을 권장한다.
5. JPA Auditing
JPA Auditing
- JPA Entity에 생성일자(createdDate), 수정일자(lastModifiedDate), 생성자(createdBy), 수정자(lastModifiedBy) 같은 감사(audit) 관련 정보를 자동으로 채워주는 기능
JPA Auditing 사용 이유
- 개발자가 일일이 날짜나 사용자 정보를 세팅할 필요 없이 자동으로 기록된다.
- 데이터 변경 이력을 쉽게 추적 가능해진다.
- 감사 로그, 변경 이력 관리에 필수적이다.
기존 코드
@Entity
public class User {
@Id
private Long id;
private String name;
private String address;
// 생성 시간
private LocalDateTime createdAt;
// 수정 시간
private LocalDateTime updatedAt;
}
@Entity
public class Item {
@Id
private Long id;
private String name;
private String description;
// 생성 시간
private LocalDateTime createdAt;
// 수정 시간
private LocalDateTime updatedAt;
}
JPA Auditing 적용예시
@MappedSuperclass
public class BaseEntity{
@Column(updatable = false)
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
@PrePersist
public void prePersist(){
LocalDateTime now = LocalDateTime.now();
created_at = now;
updated_at = now;
}
@PreUpdate
public void preUpdate() {
updated_at = LocalDateTime.now();
}
}
주요 어노테이션
어노테이션 | 역할 및 설명 |
@EnableJpaAuditing | JPA Auditing 기능을 활성화한다. 보통 @SpringBootApplication 클래스에 선언한다. |
@MappedSuperclass | 공통 매핑 정보를 제공하는 부모 클래스에 붙인다. 상속받는 엔티티에 매핑 정보가 공유된다. |
@EntityListeners(AuditingEntityListener.class) | 엔티티 생명주기 이벤트 리스너를 등록하여 생성/수정 시점에 자동으로 감사 기능을 수행한다. |
@CreatedDate | 엔티티가 최초 생성된 시점의 날짜를 자동으로 기록한다. |
@LastModifiedDate | 엔티티가 마지막으로 수정된 시점의 날짜를 자동으로 기록한다. |
@Temporal | 날짜 타입 필드의 세부 타입(DATE, TIME, TIMESTAMP)을 지정한다. |
@CreatedBy | 엔티티를 생성한 사용자 정보를 자동으로 기록한다. AuditorAware<T> 구현체가 필요하다. |
@LastModifiedBy | 엔티티를 마지막으로 수정한 사용자 정보를 자동으로 기록한다. AuditorAware<T> 구현체가 필요하다. |
6. JPA Auditing 적용하기
1) @EnableJpaAuditing 선언
- @EnableJpaAuditing 어노테이션을 통해 JPA Auditing 기능을 활성화한다.
- 보통 Spring Boot 애플리케이션의 메인 클래스 상단에 선언한다.
@EnableJpaAuditing
@SpringBootApplication
public class SpringDataJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataJpaApplication.class, args);
}
}
2) BaseEntity 클래스 생성
- @MappedSuperclass로 공통 매핑 정보를 제공하는 부모 클래스임을 선언한다.
- @EntityListeners(AuditingEntityListener.class)를 통해 Auditing 리스너를 등록한다.
- createdAt 필드는 updatable = false로 수정되지 않도록 설정한다.
- 생성 시각과 수정 시각을 자동으로 기록한다.
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAt;
@LastModifiedDate
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime modifiedAt;
}
3) BaseEntity 상속하여 엔티티에 적용
- BaseEntity를 상속받으면 createdAt, modifiedAt 필드가 자동으로 포함된다.
- 엔티티가 생성 및 수정될 때마다 날짜가 자동으로 업데이트된다.
@Entity
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}
'Spring > 강의' 카테고리의 다른 글
[📙 숙련 Spring] 3-5. Spring Data JPA 실습 (0) | 2025.05.21 |
---|---|
[📙 숙련 Spring] 3-4. Entity 설계 실습 (2) | 2025.05.21 |
[📙 숙련 Spring] 3-2. JPA Entity 만들기 (2) | 2025.05.21 |
[📙 숙련 Spring] 3-1. JPA (0) | 2025.05.20 |
[📙 숙련 Spring] 2-4. Filter (0) | 2025.05.20 |