안녕하세요! 지난 포스팅에서는 프로젝트의 기본 설정과 User, Post, Comment 엔티티를 설계하는 도메인 모델링까지 마쳤습니다.
이번 포스팅에서는 설계한 엔티티들을 실제 데이터베이스와 연결해 줄 리포지토리(Repository) 계층을 구현해 보겠습니다. 스프링 데이터 JPA의 편리한 기능 대신, JPA의 핵심인 EntityManager를 직접 사용하여 동작 원리를 깊이 있게 이해하는 데 초점을 맞추겠습니다.
### 1. JPA의 핵심: EntityManager
JPA의 모든 데이터 조작은 **EntityManager**를 통해 이루어집니다. 이 객체가 엔티티를 데이터베이스에 저장(persist), 조회(find), 수정, 삭제하는 모든 역할을 담당합니다.
스프링 부트는 spring-boot-starter-data-jpa 의존성이 있으면 EntityManager를 자동으로 생성하여 스프링 빈으로 등록해주므로, 우리는 이것을 주입받아 사용하기만 하면 됩니다.
### 2. 리포지토리 인터페이스와 구현 클래스
좋은 설계는 역할(인터페이스)과 구현(클래스)을 분리하는 것에서 시작합니다. UserRepository를 예시로 인터페이스와, JPA를 사용한 구현 클래스를 만들어 보겠습니다.
UserRepository.java (인터페이스)
public interface UserRepository {
User save(User user);
Optional<User> findById(Long id);
Optional<User> findByUsername(String username);
}
JpaUserRepository.java (구현 클래스)
EntityManager를 생성자에서 주입받아 각 메서드를 구현합니다.
public class JpaUserRepository implements UserRepository {
private final EntityManager em;
public JpaUserRepository(EntityManager em) {
this.em = em;
}
@Override
public User save(User user) {
em.persist(user); // JPA가 INSERT 쿼리를 만들어 실행하고, user 객체에 ID까지 채워줌
return user;
}
@Override
public Optional<User> findById(Long id) {
User user = em.find(User.class, id); // PK를 기준으로 조회
return Optional.ofNullable(user);
}
// ... findByUsername 구현 ...
}
### 3. JPQL (Java Persistence Query Language)
findById처럼 기본 키(PK)로 조회하는 것이 아닌, 특정 조건으로 검색할 때는 JPQL이라는 특별한 쿼리 언어를 사용해야 합니다.
- SQL과의 차이점: JPQL은 데이터베이스 테이블이 아닌, 엔티티 객체를 대상으로 쿼리를 작성합니다.
findByUsername 구현
@Override
public Optional<User> findByUsername(String username) {
// "User 엔티티(u)를 조회하는데, 그 엔티티의 username 필드가 :username 파라미터와 같은 것을 찾아라"
List<User> result = em.createQuery("select u from User u where u.username = :username", User.class)
.setParameter("username", username)
.getResultList();
return result.stream().findFirst(); // 결과를 스트림으로 변환 후 첫 번째 값을 Optional로 반환
}
### 4. SpringConfig에 리포지토리 빈 등록
마지막으로, 우리가 직접 만든 JpaUserRepository를 스프링 컨테이너가 관리할 수 있도록 SpringConfig에 빈(Bean)으로 등록합니다.
@Configuration
public class SpringConfig {
private final EntityManager em;
public SpringConfig(EntityManager em) {
this.em = em;
}
@Bean
public UserRepository userRepository() {
return new JpaUserRepository(em);
}
// PostRepository, CommentRepository도 동일한 방식으로 등록
}
PostRepository와 CommentRepository 역시 위와 동일한 패턴으로 인터페이스와 구현 클래스를 만들고, SpringConfig에 빈으로 등록해주면 리포지토리 계층이 완성됩니다.
이것으로 데이터 접근 계층의 구현을 마쳤습니다. 다음 포스팅에서는 오늘 만든 리포지토리를 사용하여 핵심 비즈니스 로직을 처리하는 서비스(Service) 계층을 구현해 보겠습니다.
'개발 공부 > 백엔드' 카테고리의 다른 글
| 제미나이와 게시판 만들기: (4) 컨트롤러 구현과 Postman API 테스트 (0) | 2025.10.05 |
|---|---|
| 제미나이와 게시판 만들기: (3) 서비스 계층 구현과 테스트 (0) | 2025.10.04 |
| 제미나이와 게시판 만들기: (1) 프로젝트 설정과 도메인 설계 (0) | 2025.10.03 |
| REST API, 개념부터 설계 원칙까지 한 번에 이해하기 (0) | 2025.10.03 |
| AOP로 공통 관심 사항 깔끔하게 분리하기 (1) | 2025.10.02 |