본문 바로가기

Spring|Spring-boot/Spring-Data-JPA11

Initialize Database Using SQL Script in Spring Boot Initialize a Database Using JPA JPA에는 DDL 생성 속성이 존재한다. 엔티티에 매핑되는 테이블이 데이터베이스에 없는 경우 애플리케이션 초기화 단계에서 적절하게 테이블을 생성해 준다. 물론 종료 시 삭제, 업데이트, 아무런 일도 하지 않도록 설정할 수 있다. spring.jpa.generate-ddl이라는 external properties을 통해 DDL 기능을 끄고 킬 수 있다. spring.jpa.hibernate.ddl-auto (enum)은 다양한 행동을 지정한다. Spring boot는 내장 데이터베이스가 감지된 경우만 created-drop 옵션으로 동작합니다. 그 외에는 none으로 기본값을 가집니다. 이러한 schema creation을 활성화시키기 위해선 org.. 2023. 6. 21.
Projections 엔티티 대신에 DTO를 편리하게 조회할 때 사용 public interface UsernameOnly { String getUsername(); } get + Entity.property 조건 List findProjectionsByUsername(@Param("username") String username); 이후 JpaRepository를 가진 인터페이스에 위와 같은 시그니처를 등록하면 끝이다. 이렇게 하면 해당 구현체가 담겨서 온다. 확인해보자. @Test public void testMember () throws Exception { //given Member member = Member.builder() .username("username") .build(); Member member2 = M.. 2022. 12. 3.
스프링 데이터 JPA 구현체를 알아보자. Rest API 서버를 만들거나, 웹 서버를 만들거나 데이터베이스를 빼놓을 수 없는 애플리케이션을 만들 때 어느샌가부터 Spring Framework 없이 만드는 것을 두려워하기 시작했다. 너무 많은 기능을 제공하고 그 기능을 통해 기존과는 비교할 수 없는 생산성을 가지고 애플리케이션을 만들 수 있기 때문인 것 같다. 데이터베이스를 다룰 때 ORM을 사용하고 자바를 사용하고 Spring Framework 기반의 프로젝트라면 Spring-data-jpa는 너무 매력적인 스프링 프로젝트이다. 그래서 오늘은 스프링 데이터 JPA 구현체에 대해 알아볼 것이다. 스프링 데이터 JPA 구현체는 다음과 같은 패키지에 존재하는 SimpleJpaRepository 이다. package org.springframework.. 2022. 12. 3.
도메인 컨버터 & 페이징과 정렬 도메인 컨버터 @GetMapping("/members/{id}") public String findMember(@PathVariable("id") Member member) { return member.getUsername(); } 응? 도메인 클래스 컨버터라고 스프링 데이터 JPA가 제공해주는 기능이다. 이는 도메인 클래스 컨버터가 중간에서 동작하여 실제 엔티티를 반환한다. 도메인 클래스 컨버터도 리파지토리를 사용해서 엔티티를 찾는다. 근데 이는 큰 문제가 하나 있는데 트랜잭션 범위 내에서 가져온 엔티티가 아니라는 점이다. 따라서 이 엔티티에 대한 속성 변경에 대해 어떠한 디비 쿼리도 발생하지 않는다. 그렇다면 단순 조회용으로 사용하기 위해선 위와 같은 방법은 좋은 선택지가 될 수 있다. 페이징과 정렬.. 2022. 12. 3.
Auditing 우리 실무 테이블엔 등록일, 수정일이 거의 무조건적으로 존재한다. 정말 이는 필요 없어 보이지만 운영에서 매우 잘 사용하는 칼럼 중 하나이다. 등록일 수정일 등록자 수정자 평균적으로 위 컬럼들은 기본적으로 깔고 가기도 한다. ORM은 기본적으로 객체를 중심적으로 본다. 이러한 공통적인 속성은 상속과 같은 개념으로 처리할 수 없을까? 당연히 존재한다. @MappedSuperclass public class JpaBaseEntity { @Column(updatable = false, insertable = true) private LocalDateTime createdAt; private LocalDateTime updatedAt; @PrePersist public void prePersist() { Loc.. 2022. 11. 30.
Custom Repository 스프링 데이터 JPA는 실제 인터페이스만 제공하고 구현체는 스프링이 자동 생성해준다. 그런데 EntityManager를 직접 사용해야 하거나 JDBC Template, MyBatis 등등 다른 기능을 사용하려면 어떻게 해야 할까? 스프링 데이터 JPA를 포기하고 별도의 리포지토리를 만들어서 사용해야 할까? 이럴 땐 다음과 같이 사용해보자. 우선 별도의 인터페이스로 커스텀하고자 하는 기능을 만들자. public interface MemberCustomRepository { List findMemberCustom(); } 이후 해당 인터페이스를 상속받는 클래스를 하나 정의하자. @RequiredArgsConstructor public class MemberCustom implements MemberCusto.. 2022. 11. 30.
JPA Hint & Lock 처음에 데이터베이스 엔진에게 알려주는 SQL 힌트인지 알았지만 그게 아니었다. 이는 JPA 구현체에게 제공하는 힌트이다. 무슨 기능이 있을까? 대표적으로 readOnly 사용할 때 사용할 수 있다. @Test public void readOnly() throws Exception { //given Member member = memberRepository.save(Member.builder().age(10).username("member1").build()); em.flush(); em.clear(); //when Member findMember = memberRepository.findById(member.getId()).get(); findMember.setAge(30); em.flush(); //t.. 2022. 11. 27.
@EntityGraph @EntityGraph는 처음 듣는 용어이다. 한번 정리해보자. @Test public void findMemberLazy() throws Exception { //given Team teamA = Team.builder().name("teamA").build(); teamRepository.save(teamA); Team teamB = Team.builder().name("teamB").build(); teamRepository.save(teamB); memberJpaRepository.save(Member.builder().age(10).username("member1").team(teamA).build()); memberJpaRepository.save(Member.builder().age(20)... 2022. 11. 27.
벌크성 수정 쿼리 최근 데이터의 순서를 사용자의 요청마다 빠르게 변경해야 할 일이 생겼다. 그런데 이 과정은 단순하게 해당 위치에 데이터를 넣는 것이 아니라 변경된 순서와 기존 순서에 비교에 따라 로직이 달라져야 한다. 기존 순서보다 변경된 순서가 크다면 변경된 순서 위치에 있는 데이터부터 기존 위치 전에 위치한 데이터를 하나씩 앞으로 변경해주어야 했고 기존 순서보다 변경된 순서가 작다면 기존 순서위치에 있는 데이터부터 변경된 순서 위치 전 데이터까지 하나씩 뒤로 밀어주어야 한다. 만약 해당 범위가 크다면 어떻게 될까? 기존 JPA를 사용하여 이를 처리할려면 다음과 같은 로직이 필요하다. 조건에 맞는 데이터 순서를 가진 모든 데이터를 가져온다. 순회하면서 데이터를 앞 혹은 뒤로 순서를 변경해준다. 여기서 중점은 순회다. .. 2022. 11. 27.
스프링 데이터 JPA JPA를 사용할 때 기본적인 CRUD는 반복적인 작업이다. 이를 위해 개발자는 손수 코드를 작성해야 한다. 엔티티가 100개라면 기본 코드를 위해 100번 반복을 해야 하는 것이다. @Repository public class MemberJpaRepository { @PersistenceContext private EntityManager em; public Member save(Member member) { em.persist(member); return member; } public void delete(Member member) { em.remove(member); } public List findAll() { return em.createQuery("select m from Member m", M.. 2022. 11. 26.