문자 : 'HELLO', 'She''s'
숫자 : 10L, 10D, 10F
Boolean : TRUE, FALSE (소문자도 됨)
ENUM : ~~.ADMIN (패키지명 필요)
엔티티 타입 : TYPE(m) = Member (상속 관계에서)
이런식으로 JPQL 에서 쓰임
String query = "select m.username, 'HELLO', TRUE from Member m where m.type = org.example.MemberType.ADMIN";
JPQL 내에서 ENUM 접근하면 길어지니깐 이런식으로 파라미터 바인딩 하는 것을 추천
String query = "select m.username, 'HELLO', TRUE from Member m where m.type = :userType";
List<Object[]> result = em.createQuery(query)
.setParameter("userType", MemberType.ADMIN)
.getResultList();
특정 상속관계에 속해있는 것만 들고오고 싶을때
em.createQuery("select i from Item i where type(i) = Book", Item.class).getResultList();
String query =
"select " +
"case when m.age <= 10 then '학생요금' " +
" when m.age >= 60 then '경로요금' " +
" else '일반요금' " +
"end " +
"from Member m";
List<String> result = em.createQuery(query, String.class).getResultList();
// result <= [ '학생요금' ]
member1.setName("changer");
member2.setName(null);
...
String query = "select coalesce(m.username, '이름 없는 회원') from Member m";
List<String> result = em.createQuery(query, String.class).getResultList();
// result -> ["changer", "이름 없는 회원"]
member1.setName("changer");
member2.setName("admin");
...
String query = "select coalesce(m.username, 'admin') from Member m";
List<String> result = em.createQuery(query, String.class).getResultList();
// result -> ["changer", null]
이외에도 여러가지 사용자 정의 함수로 추가 가능
(하이버네이트에서 많이 추가 해놓은 것도 있음. 다만 이것은 DB에 종속되어 있는 함수들임)
- 상태 필드
단순히 값을 저장하기 위한 필드
- 연관 필드
연관관계를 위한 필드
[엔티티] 단일 값 연관 필드 : @ManyToOne, @OneToOne
[컬렉션] 컬렉션 값 연관 필드 : @OneToMany, @ManyToMany
상태필드 : 경로 탐색의 끝, 탐색 x
단일 값 연관 경로 : 묵시적 내부 조인(inner join) 발생, 탐색 o
컬렉션 값 연관 경로 : 묵시적 내부 조인 발생, 탐색 x
컬렉션 값에서 탐색을 하고 싶다면?
String query = "select t.members from Team t";
List<Collection> result = em.createQuery(query, Collection.class).getResultList();
--> 명시적 조인을 활용하여 명칭을 얻은 뒤에 탐색
String query = "select m.username from Team t join t.members m";
List<String> result = em.creatQuery(query, String.class).getResultList();
(김영한 개발자님) 쿼리 튜닝이 너무 어려워짐. 묵시적으로 조인이 되다는 것... 절대로 묵시적 조인 쓰지 말것!!
sql 문과 최대한 비슷하게 짜려고 함.
(실무 조언) 항상 명시적 조인을 사용하라!!
// lazy 옵션 -> 프록시 객체로 불러옴
String query = "select m from Member m join m.team";
// lazy 옵션이 있어도 -> 원 객체로 불러옴
String query = "select m from Member m join fetch m.team";
lazy 기능이 필요할때도 있으나,
실제로 많은 member 들이 team 정보를 쓰게 되면,
사실상 fetch 조인을 써서 한번에 둘다 받아오는게 성능상 유리!
@OneToMany 조회할때. 컬렉션 조회의 경우!
String query = "select t From Team t join t.members";
List<Team> result = em.createQuery(query, Team.class).getResultList();
이 경우 members는 프록시는 아니지만, 즉각적으로 포함되어 있는 멤버 데이터를 불러오지 않음.
// fetch를 활용하여 바로 불러오기!!
String query = "select t From Team t join fetch t.members";
List<Team> result = em.createQuery(query, Team.class).getResultList();
만약 한 팀에 여러명의 멤버가 있다면, RDBS 에서는 중복 그대로 가져온다.
영속성 컨텍스트에서는 이를 그대로 받아오기는 하지만, 겹치는 부분에 대해서는 같은 주소값을 사용하여 데이터 중복을 방지함!
return 값은 중복 그대로 들어옴!
(join 하면서 데이터가 오히려 뻥튀기 되는..!)
중복 안되게 받아오는 법은? DISTINCT
- SQL 에 DISTINCT 를 추가
sql의 경우 완전이 같아야, 중복이 되는데 join 상태로는 완전히 같은 경우가 없음.- 그래서 어플리케이션에서 엔티티 중복 제거
String query = "select distinct t From Team t join fetch t.members";
List<Team> result = em.createQuery(query, Team.class).getResultList();
<Team.java>
@Batchsize
를 활용하여 member를 n개씩 batch 로딩 한다.
(default 는 lazy 로딩 <- persistenceBag인가 뭔가)
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@BatchSize(size = 100)
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
실무에서는 그냥 글로벌 세팅으로 넘겨버림.
<persistence.xml>
<property name="hibernate.default_batch_fetch_size" value="100">
성능을 이끌어 낼 수 있는 가장 주요한 파트 중에 하나이니 꼭 마스터 할 것!!!
select i from Item i
where type(i) IN (Book, Movie)
select i from Item i
where treat(i as Book).auther = 'kim'
Member m = new Member();
...
// 둘다 동일한 action
select count(m.id) from Member m
select count(m) from Member m
파라미터 바인딩으로도 넘길 수 있고 -> primary key 값으로 인식
Team teamA = new Team();
...
// 둘다 동일한 action
String query1 = "select m from Member m where m.team = :team";
em.createQuery(query1, Team.class)
.setParameter("team", teamA)
.getResultList();
String query2 = "select m from Member m where m.team.id = :teamId";
em.createQuery(query2, Team.class)
.setParameter("teamId", teamA.id)
.getResultList();
<Member.java>
@Entity
@NamedQuery(
name="Member.findByUsername",
query = "select m from Member m where m.username = :username"
)
public class Member {...}
em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username","changer")
.getResultList();
Entity 어노테이션이던, xml 이던 실무에서는 Spring data JPA 에서 따로 빼내어 만들게 될 것이니 신경 안써도 됨!
// 기존
tx.commit(); // commit 시점에 각각의 Member Entity의 age를 20으로 바꾸는 쿼리를 n번 실행
// 한꺼번에 (영속성 컨텍스트 무시)
em.createQuery("update Member m set m.age = 20").executeUpdate();
em.clear()
-> 추후 spring data jpa 에서 @Modify
로 지원