091
[JAVA] JPA, Spring Data JPA 본문
1. JPA(Java Persistence API)
- 이전 자바에서는 JDBC(Java DataBase Connectivity)라는 DB와 연결하는 API를 사용했습니다. SQL작성, 객체 변환 등을 직접 수행했어야했고 반복적으로 같은 코드를 작성했어야했기 때문에, 비지니스 로직보다 DB 코드 무게가 더 무거워지는 문제가 발생했습니다. 그 뒤로는 SQL Mapper로 MyBatis가 등장했습니다. 이는 SQL을 직접 작성하지만 매핑을 자동화하여 이전 JDBC보다 훨씬 편해졌지만 객체 지향 구조와 따로 논다는 불편함이 여전히 존재했습니다.
user.getTeam().getName(); //객체 참조
SELECT * FROM user u
JOIN team t ON u.team_id = t.id //DB 접근
-> 이러한 패러다임 불일치가 지속적으로 유지되었고 이를 해결하기 위해 ORM(Object-Relational Mapping)입니다.
- ORM은 이전에 Laravel을 다루면서 설명했던 Eloquent ORM과 같은 개념으로, DB 테이블과 하나의 Entity 클래스를 대응 시켜 다루는 방식으로 작동합니다. Hibernate, EclipseLink 등 이런 ORM 기술이 다양해지자 자바에서는 표준인 ORM인 JPA를 만든 것입니다.
User user = userRepository.findById(1L); //Spring Data JPA 사용
[PHP/Laravel] (1)DB: Eloquent ORM과 DB 파사드
01. Eloquent ORM(Object-Relational Mapping)과 DB 파사드- Eloquent은 DB 테이블을 하나의 모델 클래스로 대응시켜 다루는 방식으로, 데이터를 객체로 다루는 느낌이 강합니다. 반환 형식 자체가 전용 클래스
in-ouput91.tistory.com
+) Eloquent와 Spring Data JPA 차이
| 개념 | Laravel(PHP) | Spirng Boot(Java) | 역할 |
| ORM 엔진 | Eloquent ORM | Hibernate | 객체를 SQL로 번역하는 실질적인 엔진 |
| 매핑 클래스 | Model | Entity | 테이블과 1:1 매칭되는 객체 |
| 데이터 접근 | Query Builder | Repository | DB에 쿼리를 날리는 인터페이스/클래스 |
(1) JPA(Java Persitence API)는 실제로 동작하는 프로그램이 아니라, ORM 기술이라면 가지고 있어야하는 최소한 메서드를 적어둔 인터페이스 모음입니다. 이런 JPA를 실제로 구현한 프레임워크가 Hibernate입니다.
- Hibernate는 자바 언어를 위한 오픈 소스 객체-관계(ORM) 프레임워크로, 개발자는 SQL을 직접 작성하지 않고도 자바 객체를 데이터베이스 테이블에 매핑하여 데이터를 CRUD 할 수 있습니다.
- JPQL(Java Persistence Query Language)는 JPA 시스템 안에서 원하는 데이터를 복잡하게 검색하고 싶을 때 사용하는 객체 지향 쿼리 언어입니다. SQL은 데이터베이스의 테이블을 대상으로 쿼리하지만, JPQL은 자바 엔티티 객체를 대상으로 쿼리하므로 DB에 종속적이지 않습니다.
- 영속성 컨텍스트(Persistece Context)란 DB와 애플리케이션 사이에서 엔티티를 관리하는 메모리 공간을 의미합니다. 이 영속성 컨텍스트는 EntityManager라는 API가 관리하며, 1차 캐시(First Level Cache), 쓰기 지연(Write Behind), 변경 감지(DIrty Checking)와 같은 특징있습니다.
-> EntityManager란 영속성 컨텍스트를 관리하는 주체로, 엔티티의 저장(persist), 조회(find), 삭제(remove), 병합(merge)입니다.
EntityManager em = ...;
em.persist(user);
em.find(User.class, 1L);
em.remove(user);
1️⃣ 1차 캐시란 같은 내용을 첫 번째 조회 때는 DB에서 직접 가져와 캐시에 저장하여 두 번째 조회 때는 DB에 가지 않고 캐시에서 꺼내 사용하는 특징을 말합니다. 그래서 아래 코드처럼 객체 동일성이 보장됩니다.
User user1 = em.find(User.class, 1L);
User user2 = em.find(User.class, 1L);
user1 == user2 // true
2️⃣ 쓰기 지연은 바로 INSERT를 하지 않고 SQL을 모아서 commit 시에 한 번에 실행합니다. 이러한 처리를 Batch(데이터를 한꺼번에 묶어서 처리하는 방식) 처리라고 합니다.
em.persist(user);
3️⃣ 변경 감지란 save()를 직접 작성하지 않는 것으로, 최초 상태 스냅샷을 저장하여 commit 시에 변경을 비교하고 변경이 있으면 UPDATE를 실행합니다. 이게 바로 객체를 변경하여 DB를 변화시키는 것입니다.
User user = em.find(User.class, 1L);
user.setName("kim");
(2) Spring Data JPA란 JPA에서 스프링 부트를 사용하는 방식으로, 위에서 설명한 대로 원래 JPA를 사용하기 위해서는 영속성 컨텍스트를 관리하는 EntityManager이라는 객체를 선언하여 사용했어야합니다. 매번 이렇게 하는 것이 번거로웠기 때문에 Spring에서는 EntityManager을 자동으로 생성하고 트랙잭션을 자동으로 관리하고, Repository를 자동으로 구현해줍니다.
import org.springframework.data.jpa.repository.JpaRepository;
//JpaRepository<엔티티 클래스, PK 타입>을 상속
public interface MemberRepository extends JpaRepository<Member, Long> {
//아무것도 작성하지 않아도 기본 CRUD 사용가능
}
-> 만약 추가적으로 다른 특정조건으로 조회를 하고 싶을 때는 메서드 이름만 규칙에 맞춰 지어주면, 스프링이 알아서 JPQL을 생성하여 실행해주며 이런 메서드를 쿼리 메서드(Query Methods)라고 합니다. 하지만 만약에 조건이 3,4개로 늘어나면 메서드 이름이 너무 길어지기 때문에 직접 JPQL(@Query)을 사용하여 쿼리를 작성해줘야합니다.
//find+(엔티티명 생략 가능)+By+필드명+조건
Optional<Member> findByEmail(String email); //단순일치
Optional<Member> findByNameAndTel(String name, String tel) //AND 조건
List<Member> findByCreatedAtAfter(LocalDateTime date); //부등호
List<Member> findByIsDeletedTrue(); //Boolean
-> 직접 JPQL을 작성하는 일반적인 @Query 사용법(권장)과 네이티브 쿼리를 사용하는 방법으로 나뉩니다. 후자의 방식은 특정 DBMS에서만 사용하는 고유한 함수를 써야할 때 주로 사용하며, DB 방언의 이점을 살려 사용할 수 있지만 만약에 DBMS를 바꾸면 일일이 수정해야하는 번거로움이 있습니다.
//JPQL
@Query("SELECT m FROM Member m WHERE m.pointPassword IS NULL AND m.name = :name")
List<Member> findMembersNeedPointPassword(@Param("name") String name);
//Raw SQL(네이티브 쿼리)
@Query(value = "SELECT * FROM members WHERE is_deleted = 1 LIMIT 10", nativeQuery = true)
List<Member> findDeletedMembersLimit();'Programming Language > Java' 카테고리의 다른 글
| [Java/Spring Boot] Thymeleaf (0) | 2026.05.12 |
|---|---|
| [Java] Lombok (0) | 2026.05.05 |
| [KINO][JAVA/Spring Boot] 좌석 선정 및 예약: WebSocket 응용(3) (0) | 2026.03.29 |
| [KINO][JAVA/Spring Boot] 좌석 선정 및 예약: WebSocket 응용(2) (0) | 2026.03.28 |
| [KINO][JAVA/Spring Boot] 좌석 선정 및 예약: WebSocket 응용(1) (0) | 2026.03.24 |