Red Glitter Pointer

JPQL이란?

  • Query를 Table이 아닌 객체(엔티티) 기준으로 작성하는 객체지향 쿼리 언어
  • JPQL은 객체를 기준으로 모든 것이 움직이기 때문에, Table에 매핑되는 객체가 반드시 존재해야 함
  • 검색할 때에도 Table이 아닌 객체를 대상으로 검색해야 함.
  • Entity와 속성은 대소문자로 구분 (MEMBER <> member)
  • 별칭(alias) 사용 필수

 

💣 SQL, JPQL의 문제점

  • SQL, JPQL은 문자열이며 Type-Check가 불가능하다.
  • 컴파일 시점에 알 수 있는 방법이 없다
  • 해당 로직을 실행하기 전까지 작동 여부 확인 불가능
  • 해당 쿼리 실행 시점에 오류를 발견한다.

 

 

기존 방식(JPQL, MyBatis 등)이 모두 문자열(String) 형태로 쿼리가 작성되어 컴파일 단계에서 Type-Check가 불가하였다.

이러한 리스크를 줄이기 위해 QueryDSL 사용, 이를 통해 컴파일 단계에서 Type-Check가 가능해진 것.


 

 

QueryDSL이란?

  • SQL, JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API
  • JPA Criteria (JPQL을 자바 코드로 작성할 수 있도록 도와주는 빌더 클래스 API) 보다 편리하고 실용적이다
  • 오픈소스

 

🌟 QueryDSL의 장점

  • 자바 코드로 쿼리문을 작성하여 컴파일 시점에 오류를 발견할 수 있다
  • 문자가 아닌 코드로 작성
  • IDE의 도움으로 타입 체크나 오타를 발견할 수 있어 수정이 용이, 코드 자동 완성 기능 활용 가능
  • 동적 쿼리 구현 가능
  • 파라미터 바인딩을 자동으로 처리해주어 직접 설정할 필요가 없다

 


 

JPQL


@Test
public void startJPQL() {
	// member1을 찾아라.
	String qlString = "select m from Member m where m.username = :username";
	Member findMember = em.createQuery(qlString, Member.class)
			.setParameter("username", "member1")
			.getSingleResult();
	Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}

 

값을 넣을 때 : 를 사용해야 하고, setParameter() 로 설정해야한다

 

 

 

QueryDSL


@Test
public void startQuerydsl() {
	// member1을 찾아라.
	JPAQueryFactory queryFactory = new JPAQueryFactory(em);
	QMember m = new QMember("m");
	Member findMember = queryFactory
			.select(m)
			.from(m)
			.where(m.username.eq("member1")) // 파라미터 바인딩 처리
			.fetchOne();
	Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}

 

  1. queryFactory 로 시작한다
  2. fromQMember의 객체가 와야한다
  3. 파라미터 바인딩도 QMember의 객체에서 변수명에서 접근해서 설정한다.

 

 

객체와 테이블을 생성하고 매핑하기

@Entity : JPA가 관리할 객체

@Id : 데이터베이스 PK와 매핑

 

 

1. 등록

등록
Console

 

 

 

2. 수정

수정
Console

 

 

⚠️ 주의

1. 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유한다
2. 엔티티 매니저는 쓰레드간에 공유X (사용하고 버려야 한다)
3. JPA의 모든 데이터 변경은 트랜잭션 안에서 실행한다.

 

 

 

출처 : https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

'Backend > Spring' 카테고리의 다른 글

[Spring Boot] JPA log 설정  (0) 2023.12.30
[Spring] DAO, DTO, VO, Entity 개념 정리  (2) 2023.12.29
[JPA / 강의] Entity mapping(엔티티 매핑)  (0) 2023.12.27
[JPA] JPQL과 QueryDSL 비교  (1) 2023.12.26
[JPA / 강의] JPA의 기초  (4) 2023.12.26

JPA란?

- Java Persistance API

- 자바 진영의 ORM 기술 표준

- 애플리케이션과 JDBC 사이에서 동작

 

 

ORM이란?

- Object-relational mapping(객체 관계 매핑)

- 객체는 객체대로 설계

- 관계형 데이터베이스는 관계형 데이터베이스대로 설계

- ORM 프레임워크가 중간에서 매핑

- 대중적인 언어에는 대부분 ORM 기술이 존재

 

 

JPA는 표준 명세이다

 

JPA는 인터페이스의 모음

JPA 2.1 표준 명세를 구현한 3가지 구현체(하이버네이트, EclipseLink, DataNucleus)

 

 

 

 

JPA를 왜 사용해야 하는가?

1. SQL 중심적인 개발에서 객체 중심으로 개발
2. 생산성
3. 유지보수
4. 패러다임의 불일치 해결
5. 성능
6. 데이터 접근 추상화와 벤더 독립성
7. 표준

 

 

✔️ 생산성 - JPA와 CRUD

저장 : jpa.persist(member)

조회 : Member member = jpa.find(memberId)

수정 : member.setName("변경할 이름")

삭제 : jpa.remove(member)

 

 

✔️ 유지보수

기존에는 필드 변경 시 모든 SQL을 수정해야했음. JPA는 필드만 추가하면 됨. SQL은 JPA가 처리함! 

 

 

✔️ JPA와 연관관계, 객체 그래프 탐색

// 연관관계 저장
member.setTeam(team);
jpa.persist(member);

// 객체 그래프 탐색
Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();

 

✔️ 신뢰할 수 있는 엔티티, 계층

 

✔️  JPA와 비교하기

String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

member1 == member2; // 같다
💡 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장

 

 

✔️  JPA의 성능 최적화 기능

1. 1차 캐시와 동일성(identity) 보장

  - 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상

  - DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장

String memberId = "100";
Member m1 = jpa.find(Member.class, memberId); //SQL
Member m2 = jpa.find(Member.class, memberId); //캐시
println(m1 == m2) //true

✨ SQL 1번만 실행 

 

2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)

  ① INSERT

    - 트랜잭션을 커밋할 때까지 INSERT SQL을 모음

    - JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송

transaction.begin(); // [트랜잭션] 시작

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다.
transaction.commit(); // [트랜잭션] 커밋

 

  ② UPDATE

    - UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화

    - 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋

transaction.begin(); // [트랜잭션] 시작

changeMember(memberA);
deleteMember(memberB);
비즈니스_로직_수행(); //비즈니스 로직 수행 동안 DB 로우 락이 걸리지 않는다.

//커밋하는 순간 데이터베이스에 UPDATE, DELETE SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

 

 

3. 지연 로딩과 즉시 로딩

- 지연 로딩 : 객체가 실제 사용될 때 로딩

- 즉시 로딩 : JOIN SQL로 한 번에 연관된 객체까지 미리 조회

 

 

 

참고 : https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

+ Recent posts

loading