![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0AAt9%2FbtrB4EAh380%2F8GYk2ILgTB73AXfwuLEpk0%2Fimg.png)
JPAQueryFactory 사용 Repository에서 JPAQueryFactory를 사용하는 방법은 두가지 있다 Repository에서 직접 EntityManager를 주입 @Repository public class MemberJpaRepository { private final EntityManager em; private final JPAQueryFactory queryFactory; public MemberJpaRepository(EntityManager em) { this.em = em; this.queryFactory = new JPAQueryFactory(em); } } JPAQueryFactory 스프링 빈 등록 @Bean JPAQueryFactory jpaQueryFactory(Ent..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0GXZA%2FbtrBZ2hJ58B%2FMFZgLOiOiE7z2uABugduE1%2Fimg.png)
벌크 연산이란 쿼리 한번으로 대량의 데이터를 수정하는 것을 말한다 JPQL에서도 지원하여, querydsl도 벌크 연산에 대해 지원한다 수정 벌크 연산 @Test @DisplayName("수정 벌크 연산") void bulkUpdate() throws Exception { long count = queryFactory //영향을 받은 row 수 .update(member) .set(member.username, "비회원") .where(member.age.lt(20)) .execute(); em.flush(); em.clear(); print(); } em.flush(), em.clear()를 해주지 않으면 원하는 결과가 나오지 않게 된다 간단하게 말하면 벌크 연산은 영속성 컨텍스트를 통하지 않고 디비에..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci61DE%2FbtrBT7b3kqa%2FbSNVgxKcKmz1zFKQSGvaYK%2Fimg.png)
프로젝션? 데이터베이스에서 프로젝션은 조건에 맞는 릴레이션의 속성을 추출한다는 의미이다 따라서 우리는 원하는 속성을 추출하여 얻을 수 있다 만약에 프로젝션 대상이 한개라면 타입을 "명확"하게 정의할 수 있다 하지만 둘 이상이라면 "튜플"이나 "DTO"를 사용해야한다 순수 JPA에서의 DTO 조회 List result = em.createQuery("select new study.querydsl.dto.MemberDto(m.username, m.age) " + "from Member m", MemberDto.class) .getResultList(); 순수 JPA에서 DTO를 조회하기 위해서는 new 명령어를 이용하여 패키지 구조를 다 적어줘야함 또한, 생성자 방식만 지원함 위와 같은 이유로(내 생각엔 패..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczAP6q%2FbtrAZdYCy2y%2FvDm2Dr2xwROJpZCklYCBO0%2Fimg.png)
기본 조인 List result1 = queryFactory .selectFrom(member) .join(member.team, team) .where(team.name.eq("teamA")) .fetch(); 세타 조인 theta join을 이용해서 연관관계가 없는 필드도 조인을 할 수 있다 sql을 보면 cross가 있는데, "카테시안 곱"을 통하여 모든 엔티티를 조인한 다음, where 조건에 맞는 스키마를 찾는다 그래서 팀 2개, 멤버가 7개 이므로 카테시안 곱의 결과는 총 14개임을 알 수 있다 member, team 테이블 카테시안 곱 결과 결과 on 절 ON 절을 사용하여 "조인 대상 필터링"과 "연관관계가 없는 필드로 외부 조인"할 수 있다 조인 대상 필터링 일반적으로 JPQL에서 조인을..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmbFLX%2FbtrAmFfHEf8%2F2kh8JzKRhb1bNeMX3ihK21%2Fimg.png)
JPQL & Querydsl JPQL @Test @DisplayName("jpql 사용") void startJPQL() throws Exception { Member findMember = em.createQuery("select m from Member m " + "where m.username=:username", Member.class) .setParameter("username", "member1") .getSingleResult(); assertThat(findMember.getUsername()).isEqualTo("member1"); } Querydsl @Test @DisplayName("querydsl 사용") void startQuerydsl() throws Exception{ JPAQ..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrqNIc%2Fbtry9n2edBu%2FOGfJZHXOIjMt7Rugol8k50%2Fimg.png)
@EntityGraph? 연관관계를 맺은 엔티티들을 SQL 한번에 조회 fetch join과 매우 유사하다고 생각 연관된 엔티티를 한번에 조회하는 다양한 방법 가정 Member와 Team은 N:1 양방향 연관관계를 가짐 member1은 team1, member2는 team2, member3은 team3, member4는 team4 member, team 지연로딩 설정 List members = memberRepository.findAll(); for (Member member : members) { System.out.println("member.teamClass = " + member.getTeam().getClass()); System.out.println("member.team = " + membe..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmO87Z%2Fbtry7rDl5cX%2FBZxIAufZjXG6vKrTMZdceK%2Fimg.png)
순수 JPA 사용 조건에 맞는 엔티티들의 값을 일괄 수정하고 싶다면 벌크 연산을 사용하면 된다 public List bulkAgePlus(int age) { return em.createQuery("update Member m set m.age = m.age + 1 where m.age >= : age", Member.class) .setParameter("age", age) .getResultList(); } public List bulkAgePlus(int age) { return em.createQuery("update Member m set m.age = m.age + 1 where m.age >= : age") .setParameter("age", age) .getResultList(); } 위..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgGYL5%2FbtryOTHXV07%2Fo2krBvavbrE1F9hnKB74yK%2Fimg.png)
JPA 페이징 public List findByPage(int age, int offset, int limit) { return em.createQuery("select m from Member m where m.age = :age order by m.username desc", Member.class) .setParameter("age", age) .setFirstResult(offset) .setMaxResults(limit) .getResultList(); } public long totalCount(int age) { return em.createQuery("select count(m) from Member m where m.age = :age", Long.class) .setParameter("..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl3L0i%2FbtryOOzWU8O%2FaUjcZ6lYdKSGseJXdJr9qK%2Fimg.png)
쿼리 메서드란 repository interface에 선언되는 DB에서 정보를 찾는 메서드 spring data JPA가 제공하는 쿼리 메서드 기능 메서드 이름으로 쿼리 생성 메서드 이름으로 JPA NamedQuery 호출 @Query 어노테이션을 사용하여 repository interface에 쿼리 직접 정의 메서드 이름으로 쿼리 생성 spring data jpa를 사용하지 않는다면 작성해야할 JPQL public List findByUsernameAndAge(String username, int age) { return em.createQuery( "select m from Member m" + " where m.username = :username" + " and m.age = :age", Memb..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2EexE%2FbtrpOyd8OO4%2FKxknwkrg2kg3Q9osCunzwk%2Fimg.png)
페치 조인 페치 조인은 SQL에서 사용하는 조인의 종류가 아니다. JPQL에서 성능 최적화를 위해 제공하는 기능이다. 우리는 연관관계에서 지연 로딩을 사용한다. 하지만 페치 조인을 사용하게 되면 즉시 로딩을 하여 N+1 문제를 해결할 수 있다. 페치 조인을 할 때 나올 수 있는 값에 따라 2종류로 나눌 수 있다. 엔티티 페치 조인, 컬렉션 페치 조인 그렇다면 페치 조인을 사용할 때와 사용하지 않을 때를 비교하면서 총 4가지의 예시로 정리해보겠다. 연관관계를 그려보면 아래와 같다. 단일 값 일반 join String query1 = "select m from Member m join m.team"; List resultList = em.createQuery(query1, Member.class) .getR..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba9inI%2FbtrnQkaA7LK%2FuSuap6kk33VK9NJiEi4Dl0%2Fimg.png)
JPQL은 왜 사용하나? 우리는 DB에서 데이터를 조회할 때, em.find를 통해 쉽게 조회할 수 있다. 그런데 왜 JPQL을 사용할까? 예를 들어 member가 100명이 있는데 여기서 특정 나이 이상인 member를 조회하고 싶다. 그렇다면 우리가 할 수 있는 일은 모든 member 수 만큼 em.find를 하여, 각 member 객체의 age를 조회해야한다. 데이터의 개수가 더욱 더 늘어난다면 우린 DB에 있는 모든 member들을 모두 객체로 만들어야한다. 이 점이 불가능하기 때문에 검색 조건이 있는 JPQL을 사용하여 쉽게 조회할 수 있다. JPQL의 특징 우리가 흔히 알고 있는 SQL은 DB 테이블을 대상으로 쿼리를 짠다. 하지만 JPQL은 엔티티 객체를 대상으로 쿼리를 작성한다. 또한, 앞..
![article thumbnail](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0yyxd%2FbtrnBttkHlT%2FAzV3Y1yxZbPMWJEKOqF3Pk%2Fimg.png)
JPA의 데이터 타입 JPA의 데이터 타입은 크게 엔티티 타입과 값 타입으로 나눌 수 있다. 엔티티 타입과 값 타입의 가장 큰 차이는 식별자의 유무이다. 엔티티는 식별자를 통해 구별할 수 있지만 값은 할 수 없다. 기본 값 기본 값은 엔티티에 생명주기를 의존한다. Member가 삭제되면 age나 name이 삭제되기 때문이다. 임베디드(embedded) 임베디드 타입은 사용자가 JPA에서 새로운 값 타입을 직접 정의한 것이다. 임베디드 타입은 여러 곳에 사용할 수 있는 재사용성이 좋다. member도 주소가 필요하고, group도 주소가 필요할 때 member에 주소를 모두 쓰고, group에도 주소를 모두 쓰는 것보다 주소 임베디드 타입을 만든다면 매우 객체지향적이고 깔끔한 코드가 될 것이다. 임베디드 ..