NativeSQL

jpql์€ ํ‘œ์ค€ SQL์ด ์ง€์›ํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ๋ฒ•๊ณผ SQLํ•จ์ˆ˜๋“ค์„ ์ง€์›ํ•˜์ง€๋งŒ, ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ข…์†์ ์ธ ๊ธฐ๋Šฅ์€ ์ง€์›ํ•˜์ง€ ์•Š์Œ ์˜ˆ๋ฅผ ๋“ค๋ฉด ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋งŒ ์ง€์›ํ•˜๋Š” ํ•จ์ˆ˜, ๋ฌธ๋ฒ•, SQL์ฟผ๋ฆฌ ํžŒํŠธ ์ธ๋ผ์ธ ๋ทฐ, union, intersect ์Šคํ† ์–ด๋“œ ํ”„๋กœ์‹œ์ € ๋“ฑ๋“ฑ์ด ์žˆ๋‹ค ๋„ค์ดํ‹ฐ๋ธŒ SQL์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” JPQL์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—์„œ ์ง์ ‘ SQL์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค JPQL์„ ์‚ฌ์šฉํ•˜๋ฉด JPA๊ฐ€ SQL์„ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ๋„ค์ดํ‹ฐ๋ธŒSQL์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ •์˜ํ•œ๋‹ค๋Š” ์  ๊ทธ๋Ÿผ jdbc์˜ api๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ jpa๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋ƒ? -> ๋„ค์ดํ‹ฐ๋ธŒSQL์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๊ณ  JPA๊ฐ€ ์ง€์›ํ•˜๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๊ธฐ๋Šฅ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ -> JDBC API๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜์—ด

##๋„ค์ดํ‹ฐ๋ธŒ SQL์˜ ์‚ฌ์šฉ ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ api์—๋Š” 3๊ฐ€์ง€๊ฐ€ ์กด์žฌ

//๊ฒฐ๊ณผ ํƒ€์ž…์„ ์ •์˜
public Query createNativeQuery(String sqlString, Class resultClass);

//๊ฒฐ๊ณผ ํƒ€์ž…์„ ์ •์˜ํ•  ์ˆ˜ ์—†์„ ๋•Œ
public Query createNativeQuery(String sqlString);

public Query createNativeQuery(String sqlString, String resultSetMapping);

์—”ํ‹ฐํ‹ฐ ์กฐํšŒ

๋ญ ๊ทธ๋ ‡๊ฒŒ ๋‹ค๋ฅธ์ ์€ ์—†๋‹ค..! ๋„ค์ดํ‹ฐ๋ธŒ SQL๋กœ SQL๋งŒ ์ง์ ‘ ์‚ฌ์šฉํ•  ๋ฟ์ด์ง€ ๋‚˜๋จธ์ง€๋Š” JPQL์„ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๊ฐ™์œผ๋ฉฐ ์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ๋„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋กœ ๊ด€๋ฆฌ๋œ๋‹ค

String sql = "SELECT ID, AGE, NAME, TEAM_ID FROM MEMBER WHERE AGE > ?";

Query nativeQuery = em.createNativeQuery(sql, Member.class).setParameter(1, 20);

List<Member> resultList = nativeQuery.getResultList();

๊ฐ’ ์กฐํšŒ

๋‹จ์ˆœํ•˜๊ฒŒ ๊ฐ’์œผ๋กœ๋งŒ๋„ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค

String sql = "SELECT ID, AGE, NAME, TEAM_ID FROM MEMBER WHERE AGE > ?";

Query nativeQuery = em.createNativeQuery(sql).setParameter(1, 10); 

List<Object[]> resultList = nativeQuery.getResultList();
for(Object[] row : resultList){
    System.out.println("id = " + row[0]);
    System.out.println("age = " + row[1]);
    System.out.println("name = " + row[2]);
    System.out.println("team_id = " + row[3]);
}

์—”ํ‹ฐํ‹ฐ๋กœ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ฐ’์œผ๋กœ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด์„œ class๋ฅผ ๋‘ ๋ฒˆ์จฐ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š์€ ๋ชจ์Šต์ด๊ณ  ์กฐํšŒ๋œ ๊ฐ’์„ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์•„๋‹Œ ๊ฐ’์—๋‹ค๊ฐ€ ๋„ฃ์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— Object[]์— ๋‹ด์•„์„œ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค ์—ฌ๊ธฐ์„œ๋Š” ์Šค์นผ๋ผ ๊ฐ’๋“ค์„ ์กฐํšŒํ–ˆ์„ ๋ฟ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ !!

๊ฒฐ๊ณผ ๋งคํ•‘ ์‚ฌ์šฉ

๋งŒ์•ฝ์— ์—”ํ‹ฐํ‹ฐ์™€ ์Šค์นผ๋ผ ๊ฐ’์„ ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ๋งคํ•‘์ด ๋ณต์žกํ•ด์ง€๋ฉด @SqlResultSetMapping์„ ์ •์˜ํ•ด์„œ ๊ฒฐ๊ณผ ๋งคํ•‘์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ๋ณด์ž

String sql = "SELECT M.ID, AGE, NAME, TEAM_ID, I.ORDER_COUNT FROM MEMBER M" +
            "LEFT JOIN " +
            "(SELECT IM.ID, COUNT(*) AS ORDER_COUNT " +
            "FROM ORDERS O, MEMBER IM " +
            "WHERE O.MEMBER_ID = IM.ID) I " +
            "ON M.ID = I.ID";

Query nativeQuery = em.createNativeQuery(sql, "memberWithOrderCount");

List<Object[]> resultList = nativeQuery.getResultList();
for(object[] row : resultList){
    Member member = (Member) row[0];
    BigInteger orderCount = (BigInteger)row[1];
    
    System.out.println("member = " + member);
    System.out.println("orderCount = " + orderCount);
}

์ด๋ ‡๊ฒŒ ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๊ฒฐ๊ณผ ๋งคํ•‘ ์ •๋ณด์˜ ์ด๋ฆ„์ด ์‚ฌ์šฉ๋˜์—ˆ์Œ ์ด๋ ‡๊ฒŒ ๊ฒฐ๊ณผ ๋งคํ•‘์„ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค

@Entity
@SqlResultSetMapping(name = "memberWithOrderCount",
    entities = {@EntityResult(entityClass = Member.class),
    columns = {@ColumnResult(name = "ORDER_COUNT")}
public class Member{ ...}

memberWithOrderCount์˜ ๊ฒฐ๊ณผ ๋งคํ•‘์€ Member ์—”ํ‹ฐํ‹ฐ์™€ ORDER_COUNT ์นผ๋Ÿผ์„ ๋งคํ•‘ํ–ˆ๋Š”๋ฐ, ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์ˆ˜์˜ ์—”ํ‹ฐํ‹ฐ์™€ ๋‹ค์ˆ˜์˜ ์ปฌ๋Ÿผ์„ ์ด์–ด์ฃผ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค @EntityResult ์ด์™ธ์—๋„ @FieldResult ๋ผ๋Š” ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ ์ปฌ๋Ÿผ๋ช…๊ณผ ํ•„๋“œ๋ช…์„ ์ง์ ‘ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅ

๊ฒฐ๊ณผ ๋งคํ•‘ ์• ๋…ธํ…Œ์ด์…˜

@SqlResultSetMapping

  • name : ๊ฒฐ๊ณผ ๋งคํ•‘ ์ด๋ฆ„

  • entities : @EntityResult๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฒฐ๊ณผ๋กœ ๋งคํ•‘

  • columns : @ColumnResult๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ปฌ๋Ÿผ์„ ๊ฒฐ๊ณผ๋กœ ๋งคํ•‘

@EntityResult

  • entityClass : ๊ฒฐ๊ณผ๋กœ ์‚ฌ์šฉํ•  ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์ง€์ •

  • fields : @FieldResult์„ ์‚ฌ์šฉํ•ด์„œ ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ์„ ํ•„๋“œ์™€ ๋งคํ•‘

  • discriminatorColumn : ์—”ํ‹ฐํ‹ฐ์˜ ์ธ์Šคํ„ด์Šค ํƒ€์ž…์„ ๊ตฌ๋ถ„ํ•˜๋Š” ํ•„๋“œ(์ƒ์†ํ•  ๋•Œ ์‚ฌ์šฉ)

@FieldResult

  • name : ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์„ ํ•„๋“œ๋ช…

  • column : ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ๋ช…

@ColumnResult

  • name : ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ๋ช…

Named ๋„ค์ดํ‹ฐ๋ธŒ SQL

JPQL์—์„œ ์ฒ˜๋Ÿผ ๋„ค์ดํ‹ฐ๋ธŒSQL๋„ Named ๋„ค์ดํ‹ฐ๋ธŒ SQL์„ ์‚ฌ์šฉํ•ด์„œ ์ •์  SQL์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค

@Entity
@NamedNativeQuery(
    name = "Member.memberSQL",
    query = "SELECT ID, AGE, NAME, TEAM_ID FROM MEMBER WHERE AGE > ?", resultClass = Member.class
)
public class Member { ... }

@NamedNativeQuery ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ Named๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์šฉ์€ ์ด๋ ‡๊ฒŒ

TypedQuery<Member> nativeQuery = em.createQuery("Member.memberSQL", Member.class).setParameter(1, 20);

์‚ฌ์šฉ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ฒฐ๊ณผ ๋งคํ•‘ ์ž์ฒด๋Š”

@Entity
@SqlResultSetMapping(name = "memberWithOrderCount",
    entities = {@EntityResult(entityClass = Member.class)},
    columns = {@ColumnResult(name = "ORDER_COUNT")}
)
@NamedNativeQuery(
    name = "Member.memberWithOrderCount",
    query = "SELECT M.ID, NAME, TEAM_ID, I.ORDER_COUNT FROM MEMBER M" +
            "LEFT JOIN (SELECT IM.ID, COUNT(*) AS ORDER_COUNT " +
                        "FROM ORDERS O, MEMBER IM " +
                        "WHERE O.MEMBER_ID = IM.ID) I " +
            "ON M.ID = I.ID",
            resultSetMapping = "memberWithOrderCount"
)
public class Member {...}

Named ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ์—์„œ ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ ๋งคํ•‘๊นŒ์ง€ memberWithOrderCount์— ๋งž์ถฐ์คฌ๊ณ 

List<Object[]> resultList = em.createNamedQuery("Member.memberWithOrderCount").getResultList();

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค

@NamedNativeQuery

  • name : ๋„ค์ž„๋“œ ์ฟผ๋ฆฌ ์ด๋ฆ„(required)

  • query : SQL ์ฟผ๋ฆฌ(required)

  • hints : ๋ฒค๋” ์ข…์†์ ์ธ ํžŒํŠธ

  • resultClass : ๊ฒฐ๊ณผ ํด๋ž˜์Šค

  • resultSetMapping : ๊ฒฐ๊ณผ ๋งคํ•‘ ์‚ฌ์šฉ

๋„ค์ดํ‹ฐ๋ธŒ SQL ์ •๋ฆฌ

๋„ค์ดํ‹ฐ๋ธŒ SQL์€ JPQL์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” SQL์„ ์ˆ˜๋™์œผ๋กœ ์ง์ ‘ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ ๋Œ€๋ถ€๋ถ„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ๊ทผ๋ฐ ์ด๋ ‡๊ฒŒ ๋‚  ๊ฒƒ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ์ด์‹์„ฑ๋„ ๋–จ์–ด์ง€๊ณ  ์ข…์†์ ์ด๋ผ๋Š” ์ ..!

์Šคํ† ์–ด๋“œ ํ”„๋กœ์‹œ์ €(Stored Procedure)

๊ฐœ๋…์œผ๋กœ๋Š” ์ผ๋ จ์˜ ์ฟผ๋ฆฌ๋ฅผ ๋งˆ์น˜ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์‹คํ–‰ ํ•˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ์˜ ์ง‘ํ•ฉ์ด๋‹ค

์˜ˆ์‹œ๋กœ๋Š” ์ž…๋ ฅ๊ฐ’์„ 2๋ฐฐ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” proc_multiply๊ฐ€ ์žˆ๋Š”๋ฐ jpa๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๊ฑด

StoredProcedureQuery spq = em.createStoredProcedureQuery("proc_multiply");
spq.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);
spq.registerStoredProcedureParameter(2, Integer.class, ParameterMode.OUT);

spq.setParameter(1, 100);
spq.exeute();

Integer out = (Integer)spq.getOutputParameterValue(2);
System.out.println("out = " + out); 

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด out์€ 200

๋ญ ๋Œ€์ถฉ ์ด๋Ÿฐ ๊ฐœ๋…์— ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค๊ณ ๋งŒ ์•Œ์•„๋‘๊ณ  ๋ˆˆ์—์ข€ ๋ณด์ด๋ฉด ๋‹ค์‹œ ๊ณต๋ถ€ํ•˜์ž

Last updated

Was this helpful?