본문 바로가기

웹 프로그래밍/JPA

(19)
JPA 영속성 컨텍스트 JPA를 이해하는데 가장 중요한 용어 엔티티를 영구 저장하는 환경이라는뜻 EntityManager를 통해 영속성 컨텍스트에 접근 가능 디비와 애플리케이션의 중간에서 중개함 영속성 컨텍스트의 장점 1차 캐시(1차캐시에 저장돼서 같은 쿼리가 여러번 나가지 않음) 동일성 보장(1차캐시에서 꺼내오기때문에 동일) 트랜잭션을 지원하는 쓰기 지연(쓰기 지연 SQL에 모아두고 트랙잭션 단위에 쿼리를 한꺼번에 날림) 변경 감지(Dirty Checking: 1차 캐시에 저장할때 스냅샷을 찍어놓고 트랜잭션 커밋 시점(내부에서 flush 호출)에 만약 스냅샷과 엔티티가 다르다면 쓰기 지연 SQL에 업데이트 쿼리를 추가함) 지연 로딩(연관관계의 객체들은 필요할때 가져오도록함, 처음엔 프록시 객체로 끼워넣음) 변..
Querydsl JPQL의 단점 JPQL은 문자열을 사용해 개발자가 직접 쿼리를 작성 컴파일시에 오류를 잡아내기 어려움 동적쿼리 작성 어려움 Querydsl Querydsl은 데이터를 조회하는 여러 맥락에 대하여 같은 Java 코드로 데이터를 조회하는것을 목표로 함 자바 코드기 때문에 컴파일시 오류 검출 가능 조건으로 따로 추출하여 동적쿼리 작성이 유리 JPAQueryFactory JPQL을 빌더처럼 작성할수 있게 해주는 객체 JPA를 사용하기 때문에 EntityManager를 의존함 Spring Data JPA를 사용한다면 Bean 객체로 등록돼 있음 자세한 사용법 https://github.com/joshiaLee/Querydsl
연관관계 편의 메서드 왜 연관관계 편의 메서드로 양쪽에 값을 모두 세팅해야 하는가? 1. 1차 캐시로 인해 쿼리가 안나가고 메모리상에서 바로 꺼내질수 있음 2. 테스트 케이스 작성시 JPA없이 작성해야 할때도 있기때문이다. public void setBoard(Board board) { // 기존 연관된 board가 있으면 제거 if (this.board != null) { this.board.getComments().remove(this); } // 새로운 board 설정 this.board = board; // 새로운 board가 있으면 해당 board에 현재 comment 추가 if (board != null) { board.getComments().add(this); } }
Querydsl 중급 프로젝션: select의 대상 지정 (차원이 줄어듬) List result = quertFactory.select(member.username).from(member).fetch(); 프로젝션 대상이 둘이상이면 튜플(가급적 리포지토리 계층안에서만 사용)이나 DTO로 조회(권장) List result = quertFactory.select(member.username, member.age).from(member).fetch(); 프로젝션과 결과반환 - DTO 순수 JPA에서 DTO 조회할때는 new 명령어로 패키지 명까지 적어줘야함(귀찮음) Querydsl 빈생성 방식 -프로퍼티 접근(setter) List result = queryFactory .select(Projections.bean(MemberDt..
Querydls 기본 use_sql_comments: true 추가시 Querydls이 어떻게 JPQL로 바뀌는지 주석으로 확인 가능 검색 조건 쿼리 member.username.eq("member1") // username = 'member1' member.username.ne("member1") // username != 'member1' member.username.isNotNull() // 이름이 is not null member.age.in(10, 20) // age in (10, 20) member.age.notIn(10, 20) // age not in (10, 20) member.age.between(10, 30) // between 10, 30 member.age.goe(30) // age >= 30(grea..
스프링 데이터 JPA 메소드 이름만으로 쿼리 생성 기능(강력함): 간단한 쿼리들 해결가능 findByLastnameAndFisrtname -> where x.lastname = ?1 and x.fisrtname = ?2 findByFirstname(Is) -> where x.fisrtname = ?1 findByStartDateBetween -> where x.startDate between ?1 and ?2 findByAgeGreaterThanEqual -> where x.age >= ?1 findByFirstnameLike -> where x.firstname like ?1 findByFirstnameContaining -> where x.firstname like ?1 ('%member%') findByAgeOrderB..
JPA 활용(2) 팁 정리 @ResponseBody 데이터 자체를 Json으로 보냄 @Valid 엔티티를 검증함 엔티티가 바뀌면 API 스펙도 같이 바껴버림 -> 엔티티를 바로 쓰는것이 아니라 API 스펙에 맞춰서 별도의 DTO 클래스로 해결 -> 안정적인 운영가능 엔티티는 노출이 안되는 방향으로 설계 해야함 의존관계는 Controller -> Service -> Repository 이런식으로 한방향으로 흘러야함(단방향) Repository는 가급적 순수한 엔티티를 다루는 용 복잡한 api 화면처리는 따로 QueryRepository화 시켜서 클래스로 만듬(구별) -> 유지, 보수 DTO 안에서도 엔티티가 있으면 그것까지 DTO로 바꾸어야함 (겉과 속이 같이) 일대다(컬렉션)를 페치 조인 하는 순간 페이징이 불가함(데이터가 뻥튀기..
JPA 활용(1) 팁 정리 build.gradle 에 implementation 'org.springframework.boot:spring-boot-devtools' 추가시 리컴파일만 다시해주면 서버다시 띄울필요없이 새로고침 가능 처음 프로젝트를 만들때 Execution failed for task ':test'. ctrl+alt+s를 눌러 settings에 들어가서 테스트구동을 Gradle -> intellij로 바꿔줘야 함 @Transactional 이 테스트에 있으면 롤백됨 롤백 안되게 하려면 @RollBack(false) 쿼리의 (?, ?)을 보고싶을때 일단 yml 파일을 수정 추적 가능 org.hibernate.type : trace 아예 (?, ?)를 속성으로 대체하고 싶을때(파라미터 바인딩): 개발중에 눈에 안보이면 ..