📌
ORM(Object-relational mapping)
: 객체 관계 매핑
객체는 객체대로 설계, 관계형 데이터베이스는 관계형 데이터베이스대로 설계.
ORM 프레임워크가 중간에서 매핑해준다.JPA(Java Persistence API)
Hibernate: ORM 프레임워크, 오픈소스 소프트웨어
JPA: 현재 자바 진영의 ORM 기술 표준, 인터페이스 모음
즉, 실제로 동작하는 것은 아니며 JPA 인터페이스를 구현한 대표적 오픈소스가 Hibernate왜 JPA를 쓰는가?
- SQL 중심적인 개발에서 객체 중심으로 개발
- 생산성 (즉, 간단한 CRUD)
➡️ 예를 들어
저장: em.persist(member)
조회: Member member = em.find(memberId)
수정: member.setName("changeName")
삭제: em.remove(member)
특히나 수정이 굉장히 간단 → 객체를 변경하면 알아서 DB에 업데이트 쿼리가 전달- 유지보수
➡️ JPQL, JPA Criteria(비추), QueryDSL, 네이티브 SQL, JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용
: SQL과 굉장히 유사한 가장 단순한 조회 방법
Ex. EntityManager.find() 이 가장 단순한 방법임
그리고 필요하면 객체 그래프 탐색(a.getB().getC())를 사용하기도 한다.
JPA를 사용하면 엔티티 객체를 중심으로 개발할 수 있다.
문제는 검색 쿼리인데 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
모든 DB 데이터를 객체로 변환해 검색하는 것은 불가능하다.
애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
SQL과 문법이 유사 (SELECT
, FROM
, WHERE
, GROUP BY
, HAVING
, JOIN
지원)
JPQL
은 엔티티 객체를 대상으로 쿼리하며
SQL
은 데이터베이스 테이블을 대상으로 쿼리한다는 점이 가장 큰 차이점이다.
선생님은 실무에서 절대 쓰지 않으신다고 이런게 있구나 알고 넘어가라고 하셨다,,^^
JPQL 빌더 역할을 한다.
동적 쿼리를 구현할 때 좋으며 오타내면 컴파일 시점 바로 잡아줄 수 있어 좋다.
하지만 너무 복잡하고 실용성이 없어 대신 QueryDSL을 사용하길 권장한다.
String sql =
“SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = ‘kim’";
List<Member> resultList =
em.createNativeQuery(sql, Member.class).getResultList();
em.flush()
)프로젝트(hellojpa/jpql) 새로 생성
생성 후 pom.xml (다른 메이븐 프로젝트처럼) 세팅, resources/METE-INF/persistence.xml 세팅
참고로 사용 DB는
/~/test
(SQL과 똑같음)
select m from Member as m where m.age > 18
try {
Member member = new Member();
member.setUsername("member1");
em.persist(member);
TypedQuery<Member> query = em.createQuery("select m from Member m", Member.class); // 타입정보를 명기했기 때문에 반환 타입이 TypedQuery
Query query2 = em.createQuery("select m.username, m.age from Member m"); // 이와 같이 타입정보를 명기할 수 없는 경우도 있음
tx.commit();
} catch (Exception e){
query.getResultList()
: 결과가 하나 이상일 때, 리스트 반환
결과가 없으면 빈 리스트를 반환한다.
query.getSingleResult()
: 결과가 정확히!! 하나일 때, 단일 객체를 반환
결과가 없다면 javax.persistence.NoResultException
예외 발생
둘 이상이라면 javax.persistence.NonUniqueResultException
예외 발생
: SELECT 절에 조회할 대상을 지정하는 것
프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
SELECT m FROM Member m
: 엔티티 프로젝션(멤버 엔티티를 조회한다는 것)
SELECT m.team FROM Member m
: 엔티티 프로젝션
SELECT m.address FROM Member m
: 임베디드 타입 프로젝션 (예제에서 address가 임베디드 타입이므로)
SELECT m.username, m.age FROM Member m
: 스칼라 타입 프로젝션
SELECT m.username, m.age FROM Member m
Query 타입으로 조회
Objectp[] 타입으로 조회
new 명령어로 조회(제일 깔끔한 방법)
setFirstResult
(int startPosition): 조회 시작 위치(0부터 시작)setMaxResults
(int maxResult): 조회할 데이터 수//페이징 쿼리
String jpql = "select m from Member m order by m.name desc"; List<Member> resultList = em.createQuery(jpql, Member.class)
.setFirstResult(10) .setMaxResults(20).getResultList();
(sql 조인이랑 실행되는 건 똑같음)
📌 JOIN VS LEFT JOIN
JOIN
(INNER JOIN
) 내부조인: Table A와 Table B의 교집합을 조회
LEFT JOIN
(LEFT OUTER JOIN
) 외부조인: Table A와 Table B의 합집합을 조회
SELECT m FROM Member m [INNER] JOIN m.team t
inner는 그냥 join으로 써도 됨
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
회원은 있고 팀이 없어도 팀 데이터 다 null이고 멤버 조회 가능 ➡️ 내부 조인과의 차이
select count(m) from Member m, Team t where m.username = t.name
연관관계가 딱히 없는 걸 조인하고 싶을 때. 막조인(?)
EX) 회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인
EX) 회원의 이름과 팀의 이름이 같은 대상 외부 조인
: 일반적인 쿼리 안에서 또 쿼리를 만드는
Ex)
select m from Member m where m.age > (select avg(m2.age) from Member m2)
() 안에서 평균값을 만드는 쿼리
select m from Member m where (select count(o) from Order o where m = o.member) > 0
(예제 1은 메인 쿼리랑 서브 쿼리랑 전혀 영향을 안 끼치지만 2 예제는 그와는 다르게 메인 쿼리를 끌고 왔다.)
[NOT] EXITS(subquery): 서브쿼리에 결과가 존재하면 참
- {ALL | ANY | SOME} (subquery) 이 세가지를 섞어 쓸 수 있음
- ALL: 모두 만족하면 참
- ANY, SOME: 같은 의미. 조건을 하나라도 만족하면 참
[NOT] IN(subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참
COALESCE
: 하나씩 조회해 null이 아니면 반환NULLIF
: 두 값이 같으면 null 반환, 다르면 첫번째 값 반환select
case when m.age <= 10 then '학생요금'
when m.age >= 60 then '경로요금'
else '일반요금'
end
from Member m
select
case t.name
when '팀A' then '인센티브110%'
when '팀B' then '인센티브120%'
else '인센티브105%'
end
from Team t