|
2. CrudRepository의 주요 메소드
메소드 | 설명 | 예제 |
save(S entity) | 엔티티를 저장하거나 업데이 | userRepository.save(new User("tom", "oscar")); |
findById(ID id) | ID로 엔티티를 조회 | Optional<User> user = userRepository.findById(1L); |
findAll() | 모든 엔티티를 조회 | Iterable<User> users = userRepository.findAll(); |
count() | 전체 엔티티 수를 반환 | long userCount = userRepository.count(); |
deleteById(ID id) | ID로 엔티티를 삭제 | userRepository.deleteById(1L); |
delete(T entity) | 주어진 엔티티를 삭제 | userRepository.delete(existingUser); |
deleteAll() | 모든 엔티티를 삭제 | userRepository.deleteAll(); |
3. CrudRepository 사용 예시
3.1 엔티티 정의 : 엔티티 클래스는 @Entity 어노테이션을 사용하여 정의한다.
예)
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class User {
@Id
private Long id;
private String firstName;
private String lastName;
// Constructors, getters, setters
}
3.2 레포지토리 인터페이스 정의 : CrudRepository를 확장하여 엔티티의 기본 CRUD 작업을 수행하는 레포지토리를 정의한다.
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
// 기본 CRUD 메소드는 자동으로 상속
}
3.3 CRUD 작업 수행 : UserRepository를 사용하여 CRUD 작업을 수행할 수 있다.
@Autowired
private UserRepository userRepository;
// Create
User user = new User(1L, "tom", "oscar");
userRepository.save(user);
// Read
Optional<User> user = userRepository.findById(1L);
// Update
if (user.isPresent()) {
User existingUser = user.get();
existingUser.setLastName("james");
userRepository.save(existingUser);
}
// Delete
userRepository.deleteById(1L);
// Count
long userCount = userRepository.count();
4. CrudRepository의 상속 구조 : CrudRepository는 Repository 인터페이스를 상속받고 있으며, 이 인터페이스는 JPA의 JpaRepository, PagingAndSortingRepository와 같은 다른 더 특화된 레포지토리 인터페이스의 기반이 된다.
인터페이스 | 설 명 |
Repository | 스프링 데이터 JPA의 기본 레포지토리 인터페이스. CRUD 메소드를 정의하지 않음. |
CrudRepository<T, ID> | 기본적인 CRUD 작업을 위한 메소드 제공. |
PagingAndSortingRepository<T, ID> | 페이징과 정렬 기능을 추가한 CrudRepository의 확장. |
JpaRepository<T, ID> | JPA의 고급 기능 (예: JPA 쿼리 메소드, 배치 작업)과 페이징, 정렬 기능을 제공. |
5. PagingAndSortingRepository와 JpaRepository
- PagingAndSortingRepository : CrudRepository를 상속받고 페이징 및 정렬 기능을 추가한다.
주요 메소드:
메소드 | 설명 |
findAll(Pageable pageable) | 페이지 단위로 엔티티를 조회 |
findAll(Sort sort) | 정렬된 모든 엔티티를 조회 |
사용 예시:
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
// 기본 CRUD 메소드와 페이징 및 정렬 메소드가 모두 상속됨.
}
JpaRepository : CrudRepository와 PagingAndSortingRepository를 상속받고 JPA의 고급 기능을 추가한다.
주요 메소드:
메소드 | 설명 |
saveAll(Iterable<S> entities) | 여러 엔티티를 저장 |
findAll(Specification<T> spec) | JPA Criteria API를 사용한 동적 쿼리. |
사용 예시:
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
// 기본 CRUD, 페이징, 정렬 및 JPA 기능을 제공
}
6. CrudRepository와 JpaRepository 비교
기능 | CrudRepository | JpaRepository |
기본 CRUD 기능 | 지원 | 지원 |
페이징 및 정렬 | 미지원 | 지원 |
JPA의 고급 기능 | 미지원 | 지원 |
배치 작업 | 미지원 | 지원 |
7. CrudRepository의 메소드 오버라이드
기본 CRUD 메소드 외에도 커스텀 메소드를 추가하여 CrudRepository의 기본 동작을 확장할 수 있다.
커스텀 메소드 추가 예시: 이 메소드는 lastName으로 User를 검색하는 기능을 제공한다.
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByLastName(String lastName); // 커스텀 쿼리 메소드
}
8. Query 어노테이션을 이용한 쿼리 작성 : 복잡한 쿼리를 정의할 수 있다.
예)
public interface UserRepository extends CrudRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.firstName = ?1")
List<User> findByFirstName(String firstName); // JPQL 쿼리 작성
}
9. CrudRepository를 사용할 때의 주의점, 성능 고려사항
페이징과 정렬의 필요성
10. CrudRepository의 다양한 활용 기본 CRUD 사용
@Autowired
private UserRepository userRepository;
public void exampleCrudOperations() {
// Create
User user = new User(1L, "John", "Doe");
userRepository.save(user);
// Read
Optional<User> user = userRepository.findById(1L);
// Update
if (user.isPresent()) {
User existingUser = user.get();
existingUser.setLastName("Smith");
userRepository.save(existingUser);
}
// Delete
userRepository.deleteById(1L);
// Count
long userCount
--- 알아 보기 ----------------------------------
질문 : CrudRepository는 인터페이스인데, 예를 들어 count() 추상 메소드의 경우 count에 대한 재정의를 한 적이 없는데 어떻게 결과가 나오는 건가요?
답 : CrudRepository와 같은 인터페이스에서 추상 메소드의 구현이 없이 어떻게 메소드가 동작하는지에 대해 설명하겠습니다. 이 과정에서는 인터페이스, 구현체, 프록시 객체 등의 개념을 다루게 됩니다.
1. CrudRepository의 기본 개념
CrudRepository는 스프링 데이터 JPA에서 제공하는 기본 CRUD 작업을 정의하는 인터페이스입니다. 인터페이스는 메소드의 시그니처(메소드 이름, 매개변수, 반환 타입 등)만 정의하고, 실제 메소드의 구현은 제공하지 않습니다.
예시:
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID id);
Iterable<T> findAll();
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAll();
}
2. CrudRepository의 메소드와 구현
인터페이스의 메소드는 기본적으로 구현체(Implementation)를 제공하지 않습니다. 그러나 스프링 데이터 JPA는 이 인터페이스를 동적으로 구현하는 메커니즘을 제공합니다. 이 메커니즘은 스프링 데이터 JPA의 리포지토리 구현체가 자동으로 생성되도록 합니다.
2.1 스프링 데이터 JPA의 동적 구현
스프링 데이터 JPA는 리포지토리 인터페이스를 자동으로 구현하는 프록시 객체를 생성합니다. 이 프록시 객체는 인터페이스에 정의된 메소드의 기본적인 구현을 제공하며, 이는 JPA의 EntityManager를 통해 데이터베이스와 상호작용합니다.
리포지토리 인터페이스:
public interface UserRepository extends CrudRepository<User, Long> {
// Custom query methods can be added here
}
리포지토리의 프록시 구현체:
2.2 예시: count() 메소드
public long count();
count() 메소드는 SimpleJpaRepository 클래스에서 자동으로 구현됩니다. SimpleJpaRepository는 CrudRepository의 모든 메소드를 EntityManager를 통해 데이터베이스에 직접 쿼리하여 수행합니다. count() 메소드의 내부 구현은 다음과 같은 JPA 쿼리로 변환됩니다.
public long count() {
return entityManager.createQuery("SELECT COUNT(t) FROM " + entityClass.getName() + " t", Long.class).getSingleResult();
}
여기서 entityManager는 JPA의 EntityManager로, JPA 쿼리 API를 통해 count 쿼리를 실행하여 데이터베이스의 레코드 수를 반환합니다.
3. CrudRepository의 메소드 구현 과정
3.1 인터페이스 정의
CrudRepository의 메소드는 인터페이스에서 정의된 추상 메소드입니다.
public interface CrudRepository<T, ID> extends Repository<T, ID> {
long count();
}
3.2 리포지토리 구현
스프링 데이터 JPA는 SimpleJpaRepository 클래스를 통해 이러한 추상 메소드들을 구현합니다. SimpleJpaRepository는 EntityManager를 사용하여 실제 데이터베이스 작업을 수행합니다.
SimpleJpaRepository 예)
public class SimpleJpaRepository<T, ID> implements CrudRepository<T, ID> {
private final EntityManager entityManager;
private final Class<T> domainClass;
public SimpleJpaRepository(Class<T> domainClass, EntityManager entityManager) {
this.domainClass = domainClass;
this.entityManager = entityManager;
}
@Override public long count() {
return entityManager.createQuery("SELECT COUNT(t) FROM " + domainClass.getName() + " t", Long.class).getSingleResult(); }
// Other CRUD method implementations...
}
3.3 스프링 데이터 JPA의 자동 생성
스프링 데이터 JPA는 UserRepository 인터페이스를 기반으로 SimpleJpaRepository의 구현체를 동적으로 생성하여 프록시를 반환합니다. 이 프록시는 실제 데이터베이스 작업을 수행하는 SimpleJpaRepository의 메소드들을 호출합니다.
4. 스프링 데이터 JPA의 프록시 생성 과정
4.1 프록시 객체 생성
스프링은 리포지토리 인터페이스를 스캔하여 프록시 객체를 생성합니다. 이 프록시는 CrudRepository 인터페이스의 모든 메소드를 SimpleJpaRepository의 구현체를 통해 처리합니다.
4.2 프록시 객체와 EntityManager
프록시 객체는 EntityManager를 통해 실제 데이터베이스 작업을 수행합니다.
4.3 스프링 데이터 JPA의 자동 구성
스프링은 ApplicationContext 내에서 리포지토리 빈을 자동으로 생성합니다. 이 빈은 EntityManager를 주입받아 CrudRepository의 메소드를 실행합니다.
프록시 객체의 예시:
public class UserRepositoryProxy extends SimpleJpaRepository<User, Long> implements UserRepository {
public UserRepositoryProxy(EntityManager entityManager) {
super(User.class, entityManager);
}
}
5. CrudRepository의 기본 메소드 구현 예
5.1 findById(ID id) 메소드
@Override
public Optional<T> findById(ID id) {
return Optional.ofNullable(entityManager.find(domainClass, id));
}
**findById(ID id)**는 EntityManager의 find 메소드를 사용하여 ID로 엔티티를 조회합니다.
5.2 save(S entity) 메소드
@Override
public <S extends T> S save(S entity) {
if (entity.getId() == null) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
save(S entity)는 persist 또는 merge 메소드를 사용하여 엔티티를 저장하거나 업데이트합니다.
6. CrudRepository와 JpaRepository의 관계CrudRepository:
JpaRepository: CrudRepository의 모든 기능을 포함하고 JPA의 고급 기능을 추가로 제공합니다.
예:
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastName(String lastName); // 커스텀 쿼리 메소드
}
7. CrudRepository의 메소드 커스터마이징
7.1 커스텀 메소드 정의
리포지토리 인터페이스에 커스텀 메소드를 정의할 수 있습니다.
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByLastName(String lastName);
}
7.2 @Query 어노테이션을 활용한 커스텀 쿼리
public interface UserRepository extends CrudRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.firstName = ?1")
List<User> findByFirstName(String firstName);
}
7.3 쿼리 메소드
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByLastName(String lastName);
}
결론은
CrudRepository는 스프링 데이터 JPA에서 기본 CRUD 작업을 제공하는 인터페이스입니다.
count() 메소드와 같은 기본 메소드들은 SimpleJpaRepository와 같은 구현체에서 자동으로 제공됩니다.
스프링 데이터 JPA는 이 구현체를 프록시로 생성하여 실제 데이터베이스 작업을 처리합니다.
주요 포인트: