✍️
이런 걸
배워요!
JPA의 기본기를 탄탄하게 다질 수 있습니다.
JPA의 내부 동작 방식을 이해할 수 있습니다.
객체와 DB 테이블을 올바르게 설계하고 매핑할 수 있습니다.
실무에서 자신있게 JPA를 사용할 수 있습니다.
인프런 강의 : https://www.inflearn.com/course/ORM-JPA-Basic
강의 자료 :
https://github.com/braverokmc79/jpa-basic-lecture-file
소스 :
https://github.com/braverokmc79/ex-jpa-13-1
https://github.com/braverokmc79/jpa-shop
https://github.com/braverokmc79/ORM-JPA-Basic-jpql
[9] 객체지향 쿼리 언어1 - 기본 문법
35. 소개
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21718&tab=curriculum
목차
• 객체지향 쿼리 언어 소개
• JPQL
• 기본 문법과 기능
• 페치 조인
• 경로 표현식
• 다형성 쿼리
• 엔티티 직접 사용
• Named 쿼리
• 벌크 연산
JPA는 다양한 쿼리 방법을 지원
• JPQL
• JPA Criteria
• QueryDSL
• 네이티브 SQL
• JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용
JPQL
• JPA를 사용하면 엔티티 객체를 중심으로 개발
• 문제는 검색 쿼리
• 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
• 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
• 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검
색 조건이 포함된 SQL이 필요
JPQL
• JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
• SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
• JPQL은 엔티티 객체를 대상으로 쿼리
• SQL은 데이터베이스 테이블을 대상으로 쿼리
JPQL
//검색 String jpql = "select m From Member m where m.name like ‘%hello%'"; List<Member> result = em.createQuery(jpql, Member.class) .getResultList();
JPQL
• 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
• SQL을 추상화해서 특정 데이터베이스 SQL에 의존X
• JPQL을 한마디로 정의하면 객체 지향 SQL
JPQL과 실행된 SQL
//검색 String jpql = "select m from Member m where m.age > 18"; List<Member> result = em.createQuery(jpql, Member.class) .getResultList(
실행된 SQL select m.id as id, m.age as age, m.USERNAME as USERNAME, m.TEAM_ID as TEAM_ID from Member m where m.age>18
Criteria 소개
//Criteria 사용 준비 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Member> query = cb.createQuery(Member.class); //루트 클래스 (조회를 시작할 클래스) Root<Member> m = query.from(Member.class); //쿼리 생성 CriteriaQuery<Member> cq = query.select(m).where(cb.equal(m.get("username"), “kim”)); List<Member> resultList = em.createQuery(cq).getResultList();
Criteria 소개
문자가 아닌 자바코드로 JPQL을 작성할 수 있음
• JPQL 빌더 역할
• JPA 공식 기능
• 단점: 너무 복잡하고 실용성이 없다.
• Criteria 대신에 QueryDSL 사용 권장
QueryDSL 소개
//JPQL //select m from Member m where m.age > 18 JPAFactoryQuery query = new JPAQueryFactory(em); QMember m = QMember.member; List<Member> list = query.selectFrom(m) .where(m.age.gt(18)) .orderBy(m.name.desc()) .fetch();
QueryDSL 소개
• 문자가 아닌 자바코드로 JPQL을 작성할 수 있음
• JPQL 빌더 역할
• 컴파일 시점에 문법 오류를 찾을 수 있음
• 동적쿼리 작성 편리함
• 단순하고 쉬움
• 실무 사용 권장
네이티브 SQL 소개
• JPA가 제공하는 SQL을 직접 사용하는 기능
• JPQL로 해결할 수 없는 특정 데이터베이스에 의존적인 기능
• 예) 오라클 CONNECT BY, 특정 DB만 사용하는 SQL 힌트
네이티브 SQL 소개
String sql = “SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = ‘kim’"; List<Member> resultList = em.createNativeQuery(sql, Member.class).getResultList();
JDBC 직접 사용, SpringJdbcTemplate 등
• JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, 마이바티스등을 함께 사용 가능
• 단 영속성 컨텍스트를 적절한 시점에 강제로 플러시 필요
• 예) JPA를 우회해서 SQL을 실행하기 직전에 영속성 컨텍스트 수동 플러시
36. 기본 문법과 쿼리 API
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21719&tab=curriculum
JPQL 소개
• JPQL은 객체지향 쿼리 언어다.따라서 테이블을 대상으로 쿼리 하는 것이 아니라 엔티티 객체를 대상으로 쿼리한다.
• JPQL은 SQL을 추상화해서 특정데이터베이스 SQL에 의존하 지 않는다.
• JPQL은 결국 SQL로 변환된다.
Member
@Entity @Getter @Setter public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String username; private int age; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "TEAM_ID") private Team team; }
Address
@Embeddable @Getter public class Address { private String city; private String street; private String zipcode; public Address() { } public Address(String city, String street, String zipcode) { this.city = city; this.street = street; this.zipcode = zipcode; } @Override public int hashCode() { return Objects.hash(city, street, zipcode); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Address other = (Address) obj; return Objects.equals(city, other.city) && Objects.equals(street, other.street) && Objects.equals(zipcode, other.zipcode); } }
Order
/** * Order 주의 Order 는 예약어라 Orders 사용 */ @Entity @Getter @Table(name="ORDERS") public class Order { @Id @GeneratedValue @Column(name="ORDER_ID") private Long id; private int orderAmount; @Embedded private Address address; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="PRODUCT_ID") private Product product; }
Product
@Entity @Getter public class Product { @Id @GeneratedValue @Column(name="PRODUCT_ID") private Long id; private String name; private int price; private int stockAmount; }
Team
@Entity @Getter public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<Member>(); }
JPQL 문법
select_문 :: = select_절 from_절 [where_절] [groupby_절] [having_절] [orderby_절] update_문 :: = update_절 [where_절] delete_문 :: = delete_절 [where_절]
JPQL 문법
select m from Member as m where m.age > 18
• 엔티티와 속성은 대소문자 구분O (Member, age)
• JPQL 키워드는 대소문자 구분X (SELECT, FROM, where)
• 엔티티 이름 사용, 테이블 이름이 아님(Member)
• 별칭은 필수(m) (as는 생략가능)
집합과 정렬
select COUNT(m), //회원수 SUM(m.age), //나이 합 AVG(m.age), //평균 나이 MAX(m.age), //최대 나이 MIN(m.age) //최소 나이 from Member m
집합과 정렬
• GROUP BY, HAVING
• ORDER BY
TypeQuery, Query
TypeQuery: 반환 타입이 명확할 때 사용
• Query: 반환 타입이 명확하지 않을 때 사용
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
Query query = em.createQuery("SELECT m.username, m.age from Member m");
결과 조회 API
query.getResultList(): 결과가 하나 이상일 때, 리스트 반환
• 결과가 없으면 빈 리스트 반환
• query.getSingleResult(): 결과가 정확히 하나, 단일 객체 반환
• 결과가 없으면: javax.persistence.NoResultException
• 둘 이상이면: javax.persistence.NonUniqueResultException
파라미터 바인딩 - 이름 기준, 위치 기준
SELECT m FROM Member m where m.username=:username query.setParameter("username", usernameParam);
SELECT m FROM Member m where m.username=?1 query.setParameter(1, usernameParam);
37. 프로젝션(SELECT)
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21720&tab=curriculum
프로젝션(SELECT)
• SELECT 절에 조회할 대상을 지정하는 것
• 프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자등 기본 데이터 타 입)
• SELECT m FROM Member m -> 엔티티 프로젝션
• SELECT m.team FROM Member m -> 엔티티 프로젝션
• SELECT m.address FROM Member m -> 임베디드 타입 프로젝션
• SELECT m.username, m.age FROM Member m -> 스칼라 타입 프로젝션
• DISTINCT로 중복 제거
JpaMain
package jpashop.jpql; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import jpashop.home.domain.Member; import jpashop.home.domain.MemberDTO; import jpashop.home.domain.Team; public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf=Persistence.createEntityManagerFactory("hello"); EntityManager em=emf.createEntityManager(); //JPA 의 모든 데이터 변경은 트랜잭션 안에서 실행 되어야 한다. EntityTransaction tx=em.getTransaction(); tx.begin(); try { Member member=new Member(); member.setUsername("member1"); member.setAge(10); em.persist(member); em.flush(); em.clear(); // List<Member> result =em.createQuery("select m from Member m", Member.class).getResultList(); // // // Member findMember =result.get(0); // findMember.setAge(30); /** 조인을 할경우 다음과 같이 명시적으로 조인을 해라 **/ //List<Team> result =em.createQuery("select t from Member m join m.team t", Team.class).getResultList(); /** 타입이 여러 가지 일경우 */ /** 방법 1 */ List resultList =em.createQuery("select m.username, m.age from Member m ").getResultList(); Object o =resultList.get(0); Object[] result =(Object[]) o; System.out.println("방법 1 username = " +result[0]); System.out.println("방법 1 age = " +result[1]); /** 방법 2 */ List<Object[]> resultList2 =em.createQuery("select m.username, m.age from Member m ").getResultList(); Object[] reuslt2=resultList2.get(0); System.out.println("방법 2 username = " +reuslt2[0]); System.out.println("방법 2 age = " +reuslt2[1]); /** 방법 3 항상 new 와 jpql 적고 생성자를 호툴하듯이 하면 된다.*/ List<MemberDTO> resultList3 =em.createQuery("select new jpashop.home.domain.MemberDTO(m.username, m.age) from Member m ", MemberDTO.class).getResultList(); MemberDTO memberDTO=resultList3.get(0); System.out.println("방법 2 username = " +memberDTO.getUsername()); System.out.println("방법 2 age = " +memberDTO.getAge()); tx.commit(); }catch(Exception e) { tx.rollback(); e.printStackTrace(); }finally { em.close(); } emf.close(); } }
프로젝션 - 여러 값 조회
• SELECT m.username, m.age FROM Member m
1. Query 타입으로 조회
/** 타입이 여러 가지 일경우 */ /** 방법 1 */ List resultList =em.createQuery("select m.username, m.age from Member m ").getResultList(); Object o =resultList.get(0); Object[] result =(Object[]) o; System.out.println("방법 1 username = " +result[0]); System.out.println("방법 1 age = " +result[1]);
2. Object[] 타입으로 조회
/** 방법 2 */ List<Object[]> resultList2 =em.createQuery("select m.username, m.age from Member m ").getResultList(); Object[] reuslt2=resultList2.get(0); System.out.println("방법 2 username = " +reuslt2[0]); System.out.println("방법 2 age = " +reuslt2[1]);
3. new 명령어로 조회
/** 방법 3 항상 new 와 jpql 적고 생성자를 호툴하듯이 하면 된다.*/ List<MemberDTO> resultList3 =em.createQuery("select new jpashop.home.domain.MemberDTO(m.username, m.age) from Member m ", MemberDTO.class).getResultList(); MemberDTO memberDTO=resultList3.get(0); System.out.println("방법 2 username = " +memberDTO.getUsername()); System.out.println("방법 2 age = " +memberDTO.getAge());
• 단순 값을 DTO로 바로 조회
SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m
• 패키지 명을 포함한 전체 클래스 명 입력
• 순서와 타입이 일치하는 생성자 필요
38. 페이징
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21721&tab=curriculum
JPA는 페이징을 다음 두 API로 추상화
• setFirstResult(int startPosition) : 조회 시작 위치 (0부터 시작)
• setMaxResults(int maxResult) : 조회할 데이터 수
페이징 API 예시
//페이징 쿼리 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();
페이징 API - MySQL 방언
SELECT M.ID AS ID, M.AGE AS AGE, M.TEAM_ID AS TEAM_ID, M.NAME AS NAME FROM MEMBER M ORDER BY M.NAME DESC LIMIT ?, ?
페이징 API - Oracle 방언
SELECT * FROM ( SELECT ROW_.*, ROWNUM ROWNUM_ FROM ( SELECT M.ID AS ID, M.AGE AS AGE, M.TEAM_ID AS TEAM_ID, M.NAME AS NAME FROM MEMBER M ORDER BY M.NAME ) ROW_ WHERE ROWNUM <= ? ) WHERE ROWNUM_ > ?
package jpashop.jpql; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import jpashop.home.domain.Member; public class JpaMainPaging { public static void main(String[] args) { EntityManagerFactory emf=Persistence.createEntityManagerFactory("hello"); EntityManager em=emf.createEntityManager(); //JPA 의 모든 데이터 변경은 트랜잭션 안에서 실행 되어야 한다. EntityTransaction tx=em.getTransaction(); tx.begin(); try { for(int i=0; i<100; i++) { Member member=new Member(); member.setUsername("member"+i); member.setAge(i); em.persist(member); } em.flush(); em.clear(); List<Member> result =em.createQuery("select m from Member m order by m.age desc", Member.class) .setFirstResult(1) .setMaxResults(10) .getResultList(); System.out.println("result.size = "+result.size()); for(Member meber1: result) { System.out.println("meber = "+meber1); } tx.commit(); }catch(Exception e) { tx.rollback(); e.printStackTrace(); }finally { em.close(); } emf.close(); } }
Hibernate: /* select m from Member m order by m.age desc */ select member0_.MEMBER_ID as member_i1_0_, member0_.age as age2_0_, member0_.TEAM_ID as team_id4_0_, member0_.USERNAME as username3_0_ from Member member0_ order by member0_.age desc limit ? offset ? result.size = 10 meber = Member(id=99, username=member98, age=98, team=null) meber = Member(id=98, username=member97, age=97, team=null) meber = Member(id=97, username=member96, age=96, team=null) meber = Member(id=96, username=member95, age=95, team=null) meber = Member(id=95, username=member94, age=94, team=null) meber = Member(id=94, username=member93, age=93, team=null) meber = Member(id=93, username=member92, age=92, team=null) meber = Member(id=92, username=member91, age=91, team=null) meber = Member(id=91, username=member90, age=90, team=null) meber = Member(id=90, username=member89, age=89, team=null)
39. 조인
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21722&tab=curriculum
• 내부 조인:
SELECT m FROM Member m [INNER] JOIN m.team t
• 외부 조인:
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
• 세타 조인:
select count(m) from Member m, Team t where m.username= t.name
조인 - ON 절
• ON절을 활용한 조인(JPA 2.1부터 지원)
• 1. 조인 대상 필터링
• 2. 연관관계 없는 엔티티 외부 조인(하이버네이트 5.1부터)
Team
package jpashop.home.domain; import java.util.ArrayList; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import lombok.Getter; import lombok.Setter; @Entity @Getter @Setter public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<Member>(); }
Member
package jpashop.home.domain; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Entity @Getter @Setter @ToString public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String username; private int age; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "TEAM_ID") private Team team; public void changeTeam(Team team) { this.team=team; team.getMembers().add(this); } }
Main조인
package jpashop.jpql; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import jpashop.home.domain.Member; import jpashop.home.domain.MemberDTO; import jpashop.home.domain.Team; public class Main조인 { public static void main(String[] args) { EntityManagerFactory emf=Persistence.createEntityManagerFactory("hello"); EntityManager em=emf.createEntityManager(); //JPA 의 모든 데이터 변경은 트랜잭션 안에서 실행 되어야 한다. EntityTransaction tx=em.getTransaction(); tx.begin(); try { Team team=new Team(); team.setName("teamA"); em.persist(team); Member member=new Member(); member.setUsername("member1"); member.setAge(10); member.changeTeam(team); em.persist(member); em.flush(); em.clear(); String query="select m from Member m LEFT join m.team t on t.name='A' "; List<Member> result =em.createQuery(query, Member.class).getResultList(); System.out.println(" reuslt : "+result.size()); tx.commit(); }catch(Exception e) { tx.rollback(); e.printStackTrace(); }finally { em.close(); } emf.close(); } }
1. 조인 대상 필터링
JPQL: SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A'
SQL: SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.TEAM_ID=t.id and t.name='A'
2. 연관관계 없는 엔티티 외부 조인
• 예) 회원의 이름과 팀의 이름이 같은 대상 외부 조인
JPQL: SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
SQL: SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.username = t.name
40. 서브 쿼리
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21723&tab=curriculum
• 나이가 평균보다 많은 회원
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
서브 쿼리 지원 함수
• [NOT] EXISTS (subquery): 서브쿼리에 결과가 존재하면 참
• {ALL | ANY | SOME} (subquery)
• ALL 모두 만족하면 참
• ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참
• [NOT] IN (subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면
서브 쿼리 - 예
팀A 소속인 회원 exists
select m from Member m where exists (select t from m.team t where t.name = ‘팀A')
전체 상품 각각의 재고보다 주문량이 많은 주문들 ALL
select o from Order o where o.orderAmount > ALL (select p.stockAmount from Product p)
어떤 팀이든 팀에 소속된 회원 ANY
select m from Member m where m.team = ANY (select t from Team t)
JPA 서브 쿼리 한계
• JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
• SELECT 절도 가능(하이버네이트에서 지원)
• FROM 절의 서브 쿼리는 현재 JPQL에서 불가능
• 조인으로 풀 수 있으면 풀어서 해결
하이버네이트6 변경 사항
• 하이버네이트6 부터는 FROM 절의 서브쿼리를 지원합니다.
• 참고 링크
• https://in.relation.to/2022/06/24/hibernate-orm-61-features/
41. JPQL 타입 표현과 기타식
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21724&tab=curriculum
JPQL 타입 표현
• 문자: ‘HELLO’, ‘She’’s’
• 숫자: 10L(Long), 10D(Double), 10F(Float)
• Boolean: TRUE, FALSE
• ENUM: jpabook.MemberType.Admin (패키지명 포함)
package jpashop.home; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import jpashop.home.domain.Book; import jpashop.home.domain.Item; public class JPQL타입표현과기타식 { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); // JPA 의 모든 데이터 변경은 트랜잭션 안에서 실행 되어야 한다. EntityTransaction tx = em.getTransaction(); tx.begin(); try { Book book = new Book(); book.setPrice(10000); book.setName("JPA"); book.setIsbn("d33523"); book.setAuthor("김영한2"); book.setStockQuantity(10); em.persist(book); System.out.println("==============================="); em.createQuery("select i from Item i where type(i) = Book ", Item.class).getResultList(); System.out.println("==============================="); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { em.close(); } emf.close(); } }
• 엔티티 타입: TYPE(m) = Member (상속 관계에서 사용)
JPQL 기타
• SQL과 문법이 같은 식
• EXISTS, IN
• AND, OR, NOT
• =, >, >=, <, <=, <>
• BETWEEN, LIKE, IS NULL
42. 조건식(CASE 등등)
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21725&tab=curriculum
기본 CASE 식
select case when m.age <= 10 then '학생요금' when m.age >= 60 then '경로요금' else '일반요금' end from Member m
단순 CASE 식
select case t.name when '팀A' then '인센티브110%' when '팀B' then '인센티브120%' else '인센티브105%' end from Team t
조건식 - CASE 식
COALESCE
사용자 이름이 없으면 이름 없는 회원을 반환
select coalesce(m.username,'이름 없는 회원') from Member m
NULLIF
사용자 이름이 ‘관리자’면 null을 반환하고 나머지는 본인의 이름을 반환
select NULLIF(m.username, '관리자') from Member m
43. JPQL 함수
강의 :
https://www.inflearn.com/course/lecture?courseSlug=ORM-JPA-Basic&unitId=21726&tab=curriculum
• CONCAT
• SUBSTRING
• TRIM
• LOWER, UPPER
• LENGTH
• LOCATE
• ABS, SQRT, MOD
• SIZE, INDEX(JPA 용도)
사용자 정의 함수 호출
• 하이버네이트는 사용전 방언에 추가해야 한다.
• 사용하는 DB 방언을 상속받고, 사용자 정의 함수를 등록한 다.
select function('group_concat', i.name) from Item i
설정 방법
1.MyH2Dialect
package jpashop.home; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.type.StandardBasicTypes; public class MyH2Dialect extends H2Dialect { public MyH2Dialect() { registerFunction("group_concat", new StandardSQLFunction("group_concat", StandardBasicTypes.STRING)); } }
persistence.xml
~ <!-- <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> --> <property name="hibernate.dialect" value="jpashop.home.MyH2Dialect" /> ~
JPQL기본함수
package jpashop.home; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import jpashop.home.domain.Member; public class JPQL기본함수 { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); // JPA 의 모든 데이터 변경은 트랜잭션 안에서 실행 되어야 한다. EntityTransaction tx = em.getTransaction(); tx.begin(); try { Member member1 =new Member(); member1.setName("관리자1"); em.persist(member1); Member member2 =new Member(); member2.setName("관리자2"); em.persist(member2); em.flush(); em.clear(); String query ="select function('group_concat', m.name ) FROM Member m"; List<String> result =em.createQuery(query, String.class).getResultList(); for(String s : result) { System.out.println("s = " + s); } tx.commit(); } catch (Exception e) { tx.rollback(); } finally { em.close(); } emf.close(); } }
/* select function('group_concat', m.name ) FROM Member m */ select group_concat(member0_.name) as col_0_0_ from Member member0_ s = 관리자1,관리자2
댓글 ( 4)
댓글 남기기