JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.
JPQL 함수
JPQL 기본 함수
- JPQL이 제공하는 표준 함수이다. DB와 상관없이 그냥 사용하면 된다.
- CONCAT : 문자열을 이어주는(더하는) 함수
String query = "select concat('a', 'b') from Member m ";
// 출력 로그
Hibernate:
/* select
concat('a',
'b')
from
Member m */ select
('a'||'b') as col_0_0_
from
Member member0_
s = ab //** a와 b가 이어져서 출력된다.
concat 같은 경우는 하이버네이트에서 || 으로도 지원한다.
String query = "select 'a' || 'b' from Member m ";
그런데 위 코드를 작성하면 || 부분에 빨간 줄이 그어진다. 이 빨간 줄은 Mac 기준 option + enter → Un-inject Language/Reference를 선택하면 없어진다.
- SUBSTRING : 문자열을 잘라내는 함수
String query = "select substring(m.username,2, 3) from Member m ";
substring의 인자로는 대상, startIndex, length로 구성된다. startIndex부터 length의 길이만큼 문자열을 잘라 반환한다. 현재 member에 셋팅되어 있는 username은 Admin이므로 다음과 같이 출력된다.
Hibernate:
/* select
substring(m.username,
2,
3)
from
Member m */ select
substring(member0_.username,
2,
3) as col_0_0_
from
Member member0_
s = dmi //** 원래는 Admin이다.
만약 매개변수로 대상과 startIndex만 있을 시 startIndex에서부터 문자의 마지막까지 잘라 반환해준다.
String query = "select substring(m.username,2) from Member m ";
// 출력
s = dmin
- TRIM : 문자열의 양 끝 공백을 제거해주는 함수로 LTRIM(왼쪽 공백만 제거), RTRIM(오른쪽 공백만 제거) 모두 사용 가능하다.
member.setUsername(" Ad mi n ");
username이 위와 같은 값을 가졌을 때 trim을 사용하면 다음과 같이 출력된다.
String query = "select trim(m.username) from Member m ";
// 출력 로그
Hibernate:
/* select
trim(m.username)
from
Member m */ select
trim(member0_.username) as col_0_0_
from
Member member0_
s = Ad mi n//** 양쪽 끝 공백이 없어졌다.
- LOWER, UPPER : LOWER의 경우 모든 문자를 소문자로 변환, UPPER의 경우 모든 문자를 대문자로 변환해주는 함수이다.
member.setUsername("Admin");
String query = "select LOWER(m.username) from Member m ";
// 출력
s = admin
String query = "select upper(m.username) from Member m ";
// 출력
s = ADMIN
- LENGTH : 문자의 길이를 반환한다.
member.setUsername("Admin");
String query = "select length(m.username) from Member m ";
List<Object[]> resultList = em.createQuery(query).getResultList();
for (Object s : resultList) {
System.out.println("s = " + s);
}
// 출력
s = 5
- LOCATE : 원하는 문자의 시작 INDEX를 알려주는 함수이다.
String query = "select locate('de', 'abcdefg') from Member m ";
List<Object[]> resultList = em.createQuery(query).getResultList
// 출력
s = 4
'de'가 'abcdefg'에서 존재하면 시작 index를 반환해준다. 대상 문자열이 찾는 문자열에 없을 경우엔 0을 반환한다.
- ABS(절댓값 반환), SQRT(제곱근 반환), MOD(나눗셈 나머지 반환)
String query = "select abs(-3) from Member m ";
// 출력
s = 3
String query = "select sqrt(9) from Member m ";
// 출력
s = 3.0
String query = "select mod(10, 3) from Member m ";
// 출력
s = 1
- SIZE(컬렉션의 크기 반환), INDEX(JPA 용도)
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("Admin");
member.setAge(10);
member.setTeam(team);
member.setType(MemberType.ADMIN);
em.persist(member);
em.flush();
em.clear();
String query = "select size(t.members) from Team t";
// 출력
s = 1
index의 경우에는 일반적으로 사용할 수는 없고 값 타입 컬렉션에서 @OrderColumn를 사용했을 때 사용할 수 있는 함수이다. 근데 값 타입 컬렉션의 위치값을 구할 때 사용할 수 있는데.. 그냥 안 쓰는게 좋다.
사용자 정의 함수 호출
- JPQL에서 제공하는 표준 함수 외 DB에서 제공하는 함수를 불러서 사용하는 방법이다.
- 하이버네이트는 사용 전 방언에 추가해야 한다.
- 사용하는 DB 방언을 상속받고, 사용자 정의 함수를 등록한다.
- 하이버네이트에 대부분의 DB에서 사용하는 함수들이 다 선언되어 있기 때문에 그냥 호출해서 사용하면 된다.
예시를 위해 'group_concat'이라는 사용자 정의 함수가 있다고 치자(원래 구현되어 있는 함수임). 이 사용자 정의 함수를 등록하려면 먼저 새로운 패키지와 클래스를 만들어줘야한다.
패키지는 dialect, 클래스 명은 MyH2Dialect로 생성해준다.
public class MyH2Dialect extends H2Dialect {
public MyH2Dialect() {
registerFunction("group_concat", new StandardSQLFunction("group_concat", StandardBasicTypes.STRING));
}
}
그리고 persistence.xml도 수정해준다.
<property name="hibernate.dialect" value="dialect.MyH2Dialect"/>
그리고 실행 클래스에서 아래와 같이 사용하면 된다.
Member member = new Member();
member.setUsername("Admin1");
em.persist(member);
Member member2 = new Member();
member2.setUsername("Admin2");
em.persist(member2);
em.flush();
em.clear();
String query = "select function('group_concat', m.username) from Member m";
List<String> resultList = em.createQuery(query, String.class).getResultList();
for (String s : resultList) {
System.out.println("s = " + s);
}
// 출력
s = Admin1,Admin2
하이버네이트를 사용하는 경우엔 아래와 같이 간단하게 사용해도 된다.
String query = "select group_concat(m.username) from Member m";