스프링데이터 + JPA 112

26. 명세 (Specifications)

이제 SpringDataJpa의 전반적인 부분은 어느정도 배웠고, 이제 나머지 기능들에 대해서 소개를 좀 할건데, 이것들은 대부분 복잡도에 비해 다른 좋은 대안들이 있어서 사실 잘 안쓴다. 명세, Query By Example, Projections, 네이티브 쿼리 이렇게 4가지에 대해 배울건데, 4번째 네이티브 쿼리 빼고는 위에 3가지는 소개 하고, 왜 안쓰는지 알아볼 예정. 명세라는 것은 뭐냐, 우리가 where문에서 and, or 해서 조건같은 걸 막 넣는데, 그걸 조립해서 쓸 수 있도록 만든 개념 (근데 이건 이미 QueryDSL에서..) 그냥 나도 한번 써보는 정도는 보여 줄 거임. public interface MemberRepository extends JpaRepository, 커스텀할거야..

25. 새로운 엔티티 구별방법, isNew

@Transactional @Override public S save(S entity) { Assert.notNull(entity, "Entity must not be null"); if (entityInformation.isNew(entity)) { entityManager.persist(entity); return entity; } else { return entityManager.merge(entity); } } 이 부분에서 isNew(T) 부분에 대해서 말할거임. 기본 전략은 식별자로 식별자가 객체면 null인지로 파악 식별자가 자바 기본타입이면 0인지로 파악 Persistable 인터페이스를 구현하여 판단 로직 변경이 가능함. @Entity @Getter public class Item { @I..

24. 스프링 데이터 JPA 구현체 분석

스프링 데이터 JPA는 인터페이스를 만들어 놓으면 자동으로 구현체를 만들어 준다. 그 구현체를 분석해 볼 것이다. 애초에 예시로 구현체 모습을 제공해 주었다. SimpleJpaRepository 라는 것이다. package org.springframework.data.jpa.repository.support; 이 위치에 있다. 좀 많긴 하다. 그래도 일단 코드 한번 남겨 본다. @Repository @Transactional(readOnly = true) public class SimpleJpaRepository implements JpaRepositoryImplementation { private static final String ID_MUST_NOT_BE_NULL = "The given id mus..

23. 웹 확장 페이징과 정렬

스프링 데이터 JPA는 페이징과 정렬을 웹에서 편리하게 사용할 수 있도록 기능을 제공함. @GetMapping("/members") public Page list(Pageable pageable){ return memberRepository.findAll(pageable); } 이렇게 인자로 Pageable로 받으면, 아마 argumentResolver에 어댑팅 되면서 그 때 스프링이 PageRequest였나 그걸 생성해서 값을 채운다음 저렇게 인자로 넣어 줄 거임. 그럼 그거 받아서 저 Pageable 인자로 받는 findAll은 PagingAndSortingRepository(JpaRepository가 상속받은 인터페이스 중 하나)에 있는거임 일단 그래서 요청해보면, http://localhost:8..

22. Web확장 도메인 클래스 컨버터

스프링 데이터 JPA에서 제공해주는 웹 확장 기능 2가지가 있음. 그 중 도메인 클래스 컨버터 이게 뭐냐면, 말 그대로 컨버터다. 웹으로 받아온 걸 도메인 클래스로 변환해주는. @GetMapping("/members2/{id}") public String findMember2(@PathVariable("id") Member member){ return member.getUsername(); } 이런거다. 왜냐하면 저렇게 받는게 id니까 이런 식으로 할 수 있는거다. 스프링이 중간에 컨버팅 해주고 넣어준다. select m1_0.member_id, m1_0.age, m1_0.create_by, m1_0.created_date, m1_0.last_modified_by, m1_0.last_modified_da..

21. Auditing

Auditing 직역은 감사하다. 감사를 수행하다. 이게 무슨 기능이냐면, 보통 테이블을 만들 때 등록일, 수정일 이 두개는 기본으로 깐다. 감사하다. 라는 뉘앙스 대로 뭔가 감찰하고, 뭐 그런건데, 저런 등록일이나 수정일, 더 나아가서는 등록자나 수정자까지 자동으로 넣어주는 기능이다. 등록자 수정자는 어떤 관리자가 수정을 했고 취소를 했는지 등 시스템 관리자 id? 등으로 넣어줌. 실무에서 많이 사용함. 그럼 우선 jpa로 등록일, 수정일 적용 먼저 보통 이런 것들은 모든 테이블에 공통적으로 들어가는 사항이라, @Getter @MappedSuperclass public class JpaBaseEntity { @Column(updatable = false) private LocalDateTime crea..

20. 확장기능. 사용자 정의 리포지토리

이거는 정말 많이 쓸 것이다. 이게 뭐냐면, 우리가 기존의 SpringDataJPA에서는 메소드명으로 쿼리 지정, 뭐 JPQL직접 작성 등 여튼간에 SpringDataJPA에서가 제공해주는 방식으로만 정의할 수 있었다. 인터페이스이기 때문에. SpringDataJPA이란 JPA를 이용한 것들의 자동구현을 도와주는 라이브러리 이기 때문에. 근데 만약 우리가 jpql이 아니라 순수 sql을 이용해, jdbc template를 이용해 DB에 쿼리를 전달하고 싶다면? 아니면 QueryDSL을 쓰고 싶다면? 어딘가에 직접 우리가 그걸 구현해 줘야 한다. 아쉽게도, SpringDataJPA가 직접 QueryDSL과 뭐 연동해서 해 주는 것은 없다. 우리가 직접 구현을 해 줘야 한다. 그러면 어떻게 하느냐, 먼저, ..

19. JPA 힌트, Lock

먼저 JPA 힌트란, SQL에는 Hint 라는 것이 있다. 그러니까, SELECT employee_name FROM employees USE INDEX(employee_idx) WHERE department_id = 10; Hint 라는 것은 어떤 명령을 처리하기 위해 최적화된 방법?을 지시해 주는 것이다. mysql에서는 저렇게 use index로 힌트를 주로 제공한다고 한다. use index말고도 여러 힌트들이 있다고 한다. USE INDEX : 사용할 인덱스를 지정합니다. FORCE INDEX: USE INDEX와 비슷하지만 더 강력합니다. 비용을 고려하지 않습니다. IGNORE INDEX: 최적화 프로그램에 특정 인덱스를 무시하도록 지시합니다. 여튼, sql문에 쿼리 실행 방법에 대해 뭔가 최적..

18. @EntityGraph

엔티티 그래프 연관된 엔티티들을 한번에 조회해 오는 방법. join fetch 그거임. 엔티티 그래프 이전에, 객체 그래프 라는 것이 객체간의 연결된 관계를 보여주는 그래프임. 이런 거. 엔티티도 마찬가지임. 엔티티그래프란 엔티티간의 연결된 관계를 보여주는 그래프. join fetch라는 개념이, 이런 엔티티그래프임. join fetch라는게 이런 엔티티 그래프를 다 끌고온다는 개념임. 그래서 옛날에 join fetch 배웠을 때 fetch한 건 select에다가 별칭으로 fetch한 것의 일부분만 가져오고 그런 게 안된다고 했던 거임. 그래서 여튼, 지금 사실 Spring Data JPA가 아니라 Jpa스타일로 그냥 쿼리로 했는데, @Query("select m from Member m join fet..

17. 벌크성 수정쿼리

우리가 기존 수정은 데이터를 가져온 다음, 그걸 트랜잭션 내부에서 엔티티의 값을 변경을 하면 알아서 update 쿼리가 commit 시점에 나간다. 근데, 만약 예를 들어 전체 회사원의 연봉을 10% 올리고 싶다면? 이렇게 한번에 bulk(통으로)적으로 수정하는 걸 벌크성 수정 쿼리라고 한다. 먼저 순수 JPA에서 public int bulkAgePlus(){ return em.createQuery("update Member m set m.age= m.age + 3") .executeUpdate(); } 그냥 통으로 update 시켜 버리면 됨. 조건 넣고 싶을 경우 인자로 받던지 해서 넣으면 되고, 그리고 나름 중요한 부분이, executeUpdate() 저 부분. 저걸 해야 영향받은 row의 개수를 ..