Repository InterfaceRepositorygetOne() ↔ findById() 의 차이deleteAll() ↔ deleteAllInBatch()Like 검색 (ExampleMatcher) → queryDSL를 결국 쓰게됨Exception TranslationConsistent Exception Hierarchy
Repository Interface
Repository
public interface UserRepository extedns JpaRepository<User, Long>{ }
- JpaRepository를 이용하여 이렇게 쓸수있도록 한게 Spring data jpa
- 첫번째 Generic은 @Entity로 선언된 클래스. 두 번째 generic은 @Id의 타입
- JpaRepository가 구현하는 CrudRepository 여기에 사용하는 많은 기능들이 포함되어 있음. 이걸 가지고 extend 해서 이용하기도 함
- JpaRepositry를 구현한 UserRepository가 interface인데도 코드가 동작하는 이유 : AOP
- MethodInterceptor라는 AOP 인터페이스를 통해 JpaRepository 메서드 콜을 가로채 가서 메서드 이름 기반으로 쿼리를 작성하게 됨
getOne() ↔ findById() 의 차이
//getOne() -> lazy fetch @Test @Transactional // 이걸 안붙여주면 아래 에러가 나게 됨. session 이 없다는 에러. // could not initialize proxy [com.example.bookmanager.domain.User#3] - no Session // 붙여 주어야 session 유지가 됨 void crud(){ User user = userRepository.getOne(3L); System.out.println(user); } //getOne() 구현 부분. em.getReference()를 통해 참조값을 가져오고 실제 값이 필요할때 세션을 통해 조회 @Override public T getOne(ID id) { Assert.notNull(id, ID_MUST_NOT_BE_NULL); return em.getReference(getDomainClass(), id); } //findById 는 eager fetch @Test void crud(){ User user = userRepository.findById(3L).orElse(null); System.out.println(user); } //findByID() 구현 -> em.find() @Override public Optional<T> findById(ID id) { Assert.notNull(id, ID_MUST_NOT_BE_NULL); Class<T> domainType = getDomainClass(); if (metadata == null) { return Optional.ofNullable(em.find(domainType, id)); } LockModeType type = metadata.getLockModeType(); Map<String, Object> hints = new HashMap<>(); getQueryHints().withFetchGraphs(em).forEach(hints::put); return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints)); }
deleteAll() ↔ deleteAllInBatch()
- delete는 실행 전에 해당하는 id가 존재하는지 select를 함
- deleteAll() 은 해당하는 id들 존재하는지 하나씩 체크, 하나 delete 이걸 반복함
Like 검색 (ExampleMatcher) → queryDSL를 결국 쓰게됨
@Test void crud(){ ExampleMatcher matcher = ExampleMatcher.matching() .withIgnorePaths("name") .withMatcher("email", endsWith()); Example<User> example = Example.of(new User("ma", "fastcampus.com"), matcher); userRepository.findAll(example).forEach(System.out::println); } // 생성된 쿼리 select user0_.id as id1_0_, user0_.created_at as created_2_0_, user0_.email as email3_0_, user0_.name as name4_0_, user0_.updated_at as updated_5_0_ from user user0_ where user0_.email like ? escape ?
- withIgnorePaths 는 해당 property는 무시하고, withMacher는 email property에서 해당하는 값으로 끝나는지를 체크하도록 구성한 것임
- withIgnorePaths가 없으면 “ma”라는 name을 가지는 User를 찾게 됨(ExactMatch)
- matcher 넣지 않으면 exactmach로 적용됨
Exception Translation
[ Spring Docs ] DAO Support
Consistent Exception Hierarchy
- Spring은 기술에 specific하게 다른 exception (eg.
SQLException
) 들을 Spring 만의 exception class hierarchy(root :DataAccessException
) 안에서 translation 해서 exception을 던지게 해줌