JPA 10 # ๊ฐ์ฒด ์ฟผ๋ฆฌ ์ธ์ด, JPQL
by JiwonDev๊ฐ๋จํ CRUD๋ JPA ๋ฉ์๋๋ก ์ถฉ๋ถํ ๋์ฒด ๊ฐ๋ฅํ๋ค.
ํ์ง๋ง SQL๋ฌธ์ ๋น์ฆ๋์ค์ ๊ตฌ์กฐ์ ๋ฐ๋ผ ์กฐ๊ฑด์ด ๋ณต์กํ ์๋ ์๊ณ , ์ฑ๋ฅ ๊ฐ์ ์ด ํ์ํ ์ ์๋ค.
์ด๋ฅผ ์ํด์ JPA ์์์ฑ ์ปจํ ์คํธ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋๊ฑด ์ฌ์ค์ ๋ถ๊ฐ๋ฅํ๋ค.
์ด๋ฅผ ์ํด JPA์์๋ JPQL์ด๋ผ๋ Entity์ฉ SQL์ ์ ๊ณตํ๋ค.
๐ JPQL ํ์ค ๋ฌธ๋ฒ
SQL ํ์ค ๋ฌธ๋ฒ๊ณผ ๋งค์ฐ ์ ์ฌํ๋ค. ANSI (American National Standards Institute) ํ์ค SQL์ ๊ธฐ๋ฅ์ ์ ๋ถ ์ง์ํ๋ค.
๋จ ์ ์ํ ์ ์ Entity๋ฅผ ๋์์ผ๋ก ํ๋ ์ฟผ๋ฆฌ๋ฌธ์ด๋ค. ๋น์ฐํ ์ค์ DB Query๋ ๋ค๋ฅด๊ฒ ์ฐํ๋ค.
์ฆ, ์ถ์ํ๋ SQL์ ์ฌ์ฉํ๋๊ฑฐ๋ผ ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค SQL์ ์์กดํ์ง ์๋๋ค.
๐ JPQL ์์ฑ - JPA Criteria
JPQL์ ๊ธฐ๋ฅ์ ํ๋ถํ์ง๋ง, ์๋ฌด๋๋ String ๊ฐ์ผ๋ก ์ง์ ์ ๋ ฅํ๊ธฐ์ ๋์ ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค๊ธฐ ๋๋ฌด ๊น๋ค๋กญ๋ค.
๋ง์ฝ ํ๋ผ๋ฉํ๋ฅผ ๊ฐ์ ธ์์ ์กฐ๊ฑด์ ๋ฃ์ด์ ์ฟผ๋ฆฌ๋ฅผ ๋ฃ๋๋ค๊ณ ์๊ฐํด๋ณด์. JPQL ํธ์ถ ๋ฉ์๋๊ฐ ๋งค์ฐ ๋๋ฌ์์ง๋ค.
๊ทธ๋์ Java JPA ํ์ค์์ ์๋ฐ ์ฝ๋๋ก ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ ์๊ฒ Criteria๋ผ๋ JPQL Builder๋ฅผ ์ ๊ณตํด์ค๋ค.
โก ๊ทธ๋ฌ๋ ๋๋ฌด ์ฌ์ฉ๋ฒ์ด ๋ณต์กํด์ ์๋ฌด๋ ์์ด๋ค. ์คํ์์ค์ธ QueryDSL์ ์ฌ์ฉํ๋ค.
์์ ์ where ์ ์ ๋ณด์. ๊ฐ๋จํ ์ฟผ๋ฆฌ๋ ์ ๋ ๊ฒ ๋์ค๋๋ฐ, ์กฐ๊ฑด์ด ์กฐ๊ธ๋ง ์ถ๊ฐ๋๋ ์ฌ์ฉํ๊ธฐ๊ฐ ๋๋ฌด ์ด๋ ต๋ค.
// 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”));
// EntityManager์ Criteria ์ฟผ๋ฆฌ ์ ๋ฌ
List<Member> resultList = em.createQuery(cq).getResultList();
๐ QueryDSL (์คํ์์ค)
์ค์ ์ ์กฐ๊ธ ๊ท์ฐฎ์ง๋ง, Criteria์ ๋นํด์ ์ฌ์ฉํ๊ธฐ ๋งค์ฐ ํธํ๋ค.
๋ํ ์๋ฐ ์ฝ๋๋ก ์์ฑ๋์๊ธฐ์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ , ์ปดํ์ผ ์์ ์์ ๋ง์ ์ค๋ฅ๋ฅผ ์ก์ ์ ์๋ค.
// Factory ์์ฑ
JPAFactoryQuery query = new JPAQueryFactory(em);
//select m from Member m where m.age > 18
QMember m = QMember.member;
List<Member> list =
query.selectFrom(m)
.where(m.age.gt(18))
.orderBy(m.name.desc())
.fetch();
QueryDSL๋ ์ ๋๋ก ๊ณต๋ถํ๋ฉด JPA๊ธ ๋ถ๋์ด ๋์ค๋ฏ๋ก, ์ด ์ ๋๋ง ์๊ฐํ๊ณ ๋์ด๊ฐ๋๋ก ํ๊ฒ ๋ค.
์ฐธ๊ณ ๋ก ์ด๋ Java JPA ํ์ค ๊ธฐ์ ์ด ์๋๋ผ ์คํ์์ค์ด๋ค.
๋ค๋ง Criteria๋ QueryDSL์ด๋ ๊ฒฐ๊ตญ JPQL ์ ์์ฑํด์ฃผ๋ ๋๊ตฌ์ด๋ค.
JPQL์ ๋์์ ์ดํดํ๊ณ ์ ์ฌ์ฉํ ์ค ์๋ค๋ฉด ์์ ๊ฐ์ ๋๊ตฌ๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ค. (์ด๊ธฐ์ค์ ๋ง ์กฐ๊ธ ๊ท์ฐฎ์ ๋ฟ)
๐ ๋ค์ดํฐ๋ธ SQL
Oracle Connect by์ ๊ฐ์ด ํ์ค SQL๋ฌธ๋ฒ(ANSI)๋ฅผ ๋ฒ์ด๋๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ณ ์ถ๊ฑฐ๋
์ ๋ง ์ฟผ๋ฆฌ๋ก์ง์ด ๋ณต์กํด์ ์ง์ ์ฉ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฌ๊ณ ์ถ์ ๊ฒฝ์ฐ ์ฌ์ฉํ๋ค.
- ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ง ์ง์ํ๋ ํจ์, ๋ฌธ๋ฒ
- SQL ์ฟผ๋ฆฌ ํํธ
- ์ธ๋ผ์ธ ๋ทฐ, UNION, INTERSECT
- ์คํ ์ด๋ ํ๋ก์์
์์ ๊ฐ์ ์ด์ ๋ก JPQL์ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ, Native SQL์ ํตํด ์ง์ SQL์ ์์ฑํ ์ ์๋ค.
String sql = "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME =`kim`";
List<Member> resultList = em.createNativeQuery(sql, Member.class).getResultList();
์ด๋ ธํ ์ด์ ์ ์ด์ฉํ๋ฉด ์กฐ๊ธ ๋ ์ฝ๊ฒ ์ ์ฉ ๊ฐ๋ฅํ๋ค.
@Entity
@NamedNativeQuery(
name = "Member.memberSQL",
query = "SELECT ID, AGE, NAME, TEAM_ID " +
"FROM MEMBER WHERE AGE > ?",
resultClass = Member.class
)
public class Member {.. }
TypedQuery<Member> nativeQuery =
em.createNamedQuery("Member.memberSQL", Member.class)
.setParameter(1, 20);
์ด๋ ธํ ์ด์ ์ผ๋ก ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ค. JDBC๋ฅผ ์ง์ ์ฐ๋ ๊ฒ๊ณผ ๋ค๋ฅธ ์ ์ Native SQL ์ฌ์ฉ ์ ์ํฐํฐ๋ฅผ ์กฐํํ๊ณ , JPA๊ฐ ์ง์ํ๋ ์์์ฑ ์ปจํ ์คํธ์ ๊ธฐ๋ฅ์ ๊ทธ๋๋ก ์ด์ฉ ๊ฐ๋ฅํ๋ค.
์ฐธ๊ณ ๋ก ์ ์ ํ๊ฒ ์ค์ ๋ง ํ๋ค๋ฉด JPA์ ๋๊ฐ์ด ๊ฒฐ๊ณผ ๋งคํ( getResultList() )์ผ๋ก ๋ฐ์์ฌ ์๋ ์๋ค.
@Entity
@SqlResultSetMapping( name = "memberWithOrderCount",
entities = {@EntityResult (entityClass = Member.class)},
columns = {@ColumnResult (name = "ORDER_COUNT")}
)
@NamedNativeQuery(
name = "Member.memberWithOrderCount", // ๋ค์๋ ์ฟผ๋ฆฌ ์ด๋ฆ(ํ์)
query = "SELECT M.ID, AGE, NAME, TEAM_ID, I.ORDER_COUNT" + // SQL ์ฟผ๋ฆฌ(ํ์)
"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",
SqlResultSetMapping = "memberWithOrderCount" // ๊ฒฐ๊ณผ ๋งคํ ์ฌ์ฉ
)
public class Member { ... }
List<Object[]> resultList =
em.createNamedQuery("Member.memberWithOrderCount")
.getResultList();
๐ JDBC ์ง์ ์ฌ์ฉ (MyBatis, SpringJdbcTemplate๊ณผ ํจ๊ป ์ฌ์ฉ)
์์ JPA๋ฅผ ์๊ฑฐ์น๊ณ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ.
๊ทธ๋ฅ ์ฌ์ฉํ๋ ๊ฑฐ๋ค. ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์๊ฑฐ์น๊ณ ์ง์ ์กฐํํ๋ค.
๊ฒฐ๊ตญ JPA๋ ์ ์์ค์์๋ JDBC๋ก ๋์ํ๋ค. ์ ์ฌ์ฉํ๋ค๋ฉด JPA์ JDBC๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
์ค๋ฌด์์๋ ์ฟผ๋ฆฌ๊ฐ ๋ณต์กํด์ง๊ฑฐ๋ ์ฑ๋ฅ ํ๋์ด ํ์ํ๋ค๋ฉด SpringJdbcTemplate์ผ๋ก JPA์ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
๋ค๋ง JDBC๋ฅผ ์ง์ ์ฌ์ฉํ๋๊ฑด ์์์ฑ ์ปจํ ์คํธ๋ฅผ ๊ฑฐ์น์ง ์์ผ๋ JPA์ ํจ๊ป ์ฌ์ฉํ๋ค๋ฉด DB์ ๋ฐ์๋์๋์ง ์ ํ์ธํ๊ณ ์ฌ์ฉํด์ผํ๋ค. (์๋ flush)
๐ ์์ฝ
๋ณดํต
- JPQL
- QueryDSL
- JDBC API (SpringJdbcTemplate) - ๋จ ์ฟผ๋ฆฌ๊ฐ ์์ฒญ ๋ณต์กํ ๊ฒฝ์ฐ. ๋๋ถ๋ถ์ QueryDSL ์ ์์ ์ฒ๋ฆฌ ๊ฐ๋ฅ
์ด๋ ๊ฒ 3๊ฐ์ง๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ค.
๐ JPQL ๋ฌธ๋ฒ
๐ ๊ธฐ๋ณธ ๋ฌธ๋ฒ
- select m from member as m m.age > 18
๋ฐ๋์ ๋ณ์นญ(m)์ ๋ฃ์ด์ฃผ์ด์ผํ๋ค. [as m]์ ์๋ตํ๋๋ผ๋ ํ์ด๋ฒ๋ค์ดํธ๋ ๋ฌธ์ ๊ฐ ์์ง๋ง, ํ์ค ๋์์ ์๋. - ์ํฐํฐ์ ์์ฑ (Member, m.age)๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๋ค.
- JPQL ๋ฌธ๋ฒ ํค์๋ (SELECT, from)๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๋๋ค.
- ๋น์ฐํ๊ฑฐ์ง๋ง FROM Entity ๋ก ์ฌ์ฉํด์ผํ๋ค. ํ ์ด๋ธ ์ด๋ฆ์ ์ฐ๋๊ฒ ์๋๋ค. ์ํฐํฐ์ ๋ํ ์ถ์ํ๋ ์ฟผ๋ฆฌ์ด๋ค.
๊ทธ ์ธ COUNT, SUM๋ฑ์ ์ค๋ช ์ด ํ์ ์์์ ๋๋ก ์ฌ์ฉ๋ฒ๋ ์ง๊ด์ ์ด๋ค.
select
COUNT(m), //ํ์์
SUM(m.age), //๋์ด ํฉ
AVG(m.age), //ํ๊ท ๋์ด
MAX(m.age), //์ต๋ ๋์ด
MIN(m.age) //์ต์ ๋์ด
from Member m
๐ ์ฟผ๋ฆฌ์คํ๊ณผ ๊ฒฐ๊ณผ ๋ฐํ
๋ฐํ ํ์ ์ด ๋ช ํํ์ง ์๋ค๋ฉด Query ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ค.
์) select m.username, m.age from Member m โก String(username)๊ณผ int(age)๋ฅผ ํจ๊ป ์กฐํ. ํ์ ์ ์ ์ ์์.
Query query =
em.createQuery("SELECT m.username, m.age from Member m");
๋ฐํํ์ ์ ์ด๋ฏธ ์๊ณ ์๋ค๋ฉด ์ ๋ค๋ฆญ์ธ TypeQuery๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
์ด ๊ฒฝ์ฐ createQurey ๋ฉ์๋์ 2๋ฒ์งธ ์ธ์์ ํ์ ์ ๋๊ฒจ์ฃผ๋ฉด ๋๋ค.
TypedQuery<Member> query =
em.createQuery("SELECT m FROM Member m", Member.class);
๊ฒฐ๊ณผ ์กฐํ๋ ์๋์ ๊ฐ์ด ํ ์ ์๋ค.
query.getResultList(); // ์ปฌ๋ ์
. ๊ฐ์ด ํ๋ ์ด์, ๊ฒฐ๊ณผ๊ฐ ์๋ค๋ฉด ๋น ๋ฆฌ์คํธ ๋ฐํ
query.getSingleResult(); // ๋จ์ผ๊ฐ์ฒด. ๊ฐ์ด ๋จ ํ๋, ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ ๋ ์ด์์ด๋ฉด ์์ธ๋ฅผ ๋ฐํ
/* javax.persistence.NoResultException :: ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.
javax.persistence.NonUniqueResultException :: ๊ฒฐ๊ณผ๊ฐ ์ ๋ํฌํ์ง ์์ต๋๋ค. (์ฌ๋ฌ๊ฐ ๋ฐํ) */
๋ค๋ง getSingleResult()๋ ๋ ผ๋์ด ๋ง์ ๋ฉ์๋์ด๋ค.
์์ธ๋ฅผ ๋ฐํํ๋ฉด try - catch๋ฌธ์ผ๋ก ๋ถ๊ธฐ๋ฅผ ์์ฑํด์ค์ผํ๋๋ฐ, ์ด๊ฒ ์ฌ๋ฌ๋ฒ ๋ฐ๋ณต๋๋ฉด ์๋นํ ๋ฒ๊ฑฐ๋กญ๊ธฐ ๋๋ฌธ. ๊ทธ๋์ Spring Data JPA์๋ ์ด๋ฅผ ์ถ์ํ์์ผ null์ด๋ Optional์ ๋ฐํํ๋๋ก ๋์ํ๋ค. (๋ด๋ถ ์ฝ๋์์ JPA catch๋ฅผ ์ก์์ ์ฒ๋ฆฌํ๋ค.)
๐ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ
์ด๋ฆ ๊ธฐ์ค ๋ฐ์ธ๋ฉ :name
TypedQuery<Member> query =
em.createQuery("SELECT m FROM Member m where m.username=:username ", Member.class);
// ์ฟผ๋ฆฌ ํ๋ผ๋ฉํ ์
๋ ฅ
query.setParameter("username", usernameParam);
์์น ๊ธฐ์ค ๋ฐ์ธ๋ฉ ?n - ๋ค๋ง ์ฌ์ฉํ์ง๋ง๊ฒ. ์์๋ฅผ ๋ฐ๊พธ๋ฉด ๋ฒ๊ทธ๊ฐ ์ฝ๊ฒ ๋ฐ์ํจ.
TypedQuery<Member> query =
em.createQuery("SELECT m FROM Member m where m.username=?1 ", Member.class);
// ์ฟผ๋ฆฌ ํ๋ผ๋ฉํ ์
๋ ฅ
query.setParameter(1, usernameParam);
๋ค๋ง ์์ ๊ฐ์ด ์ฟผ๋ฆฌ๋ฅผ ๋ฉ์๋๋ก ๋ถ๋ฆฌํด์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๋ค.
๋ฉ์๋ ์ฒด์ด๋์ ์ด์ฉํด ํ๋ฒ์ ์ ๋ ๊ฑธ ๊ถ์ฅํ๋ค.
em.createQuery("SELECT m FROM Member m where m.username=:username ", Member.class)
.setParameter("username", "member1")
.getSingleResult();
๐ ํ๋ก์ ์ (Projection)
ํ๋ก์ ์ ์ Select ์ ์ ์กฐํํ ๋์์ ์ง์ ํ๋ ๊ฒ์ ์๋ฏธํ๋ค. DB ํ๋ก์ ์ ์ด๋ ๋น์ทํ ์๋ฏธ.
ํ๋ก์ ์ ๋์: ์ํฐํฐ, ์๋ฒ ๋๋ ํ์ , ์ค์นผ๋ผ ํ์ (์ซ์, ๋ฌธ์๋ฑ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์ )
๐ฉํด์ฆ - ์๋์ ์ฟผ๋ฆฌ๋ Member ๊ฐ์ฒด์ list๋ฅผ ๋ฐํํ๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ฆฌ์คํธ ์์ ์๋ ๊ฐ๊ฐ์ 'Member' ๊ฐ์ฒด๋ ์์์ฑ ์ปจํ ์คํธ์ ๊ด๋ฆฌ๊ฐ ๋ ๊น? ์๋ ๊น?
์ ๋ต : ๋๋ค. List ์์ ์๋ ๋ชจ๋ ๊ฐ์ฒด๊ฐ ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋๋ค.
๊ทธ๋์ ์ํฐํฐ ํ๋ก์ ์ ์ด๋ผ๋ ๋ง๋ก ๋ฐ๋ก ์ธ๊ธํ๋ ๊ฒ์ด๋ค. ์ด๋ ๋น์ฐํ ์ ์ฅ๋๋๊ฒ ์๋๋ค.
๋น์ฐํ๊ฑฐ์ง๋ง ์๋ฒ ๋๋ ํ์ ์ '๊ฐ' ์ด๊ธฐ ๋๋ฌธ์ ์กฐํํ ๋ ์์๋ Entity๋ฅผ ์ด์ฉํด์ ๊ฐ์ ธ์์ผํ๋ค.
em.createQuery("SELECT o.address FROM Order o", Address.class)
// SELECT address FROM Address a ๋ ๋ถ๊ฐ๋ฅ.
์ค์นผ๋ผ ํ์ (๊ทธ๋ฅ ๊ฐ)์ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด๋๋ค.
em.createQuery("SELECT m.name FROM Member m")
๊ทธ๋ฐ๋ฐ ๋ง์ฝ ๊ฐ์ด 2๊ฐ๊ฐ ๋๋๋ค๋ฉด ์ด๋ป๊ฒ ๋ฐ์์์ผํ ๊น? ์๋ฒ ๋๋ ํ์ ์ Class๋ก ๋ฌถ์ฌ์์ง๋ง ์ค์นผ๋ผ๋ ๊ทธ๋ฅ ๊ฐ์ธ๋ฐ?
em.createQuery("SELECT m.name, m.age FROM Member m") // name(String)๊ณผ age(Int)๋ฅผ ํจ๊ป ๋ฐ์์ค๋๋ฒ??
์ด ๋๋ TypeQuery ๋์ ๋ฅผ ๊ทธ๋ฅ Query๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
๊ทธ๋ผ ๋ด๋ถ์ ์ผ๋ก Object 2์ฐจ์ ๋ฐฐ์ด์ด ๋ฐํ๋๋ค.
์ฐธ๊ณ ๋ก List<Object[]>๋ก ์ฌ์ฉํ๋ฉด TypeQuery๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ ธ์ค๊ฒ๋๋ค. ์ฌ์ฉ๋ฒ์ ๋์ผํ๋ค.
List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m");
.getResultList();
Object[] result = resultList.get(0);
// result[0] == username1
// result[1] == age1
์กฐ๊ธ ๋ ๊น๋ํ ๋ฐฉ๋ฒ์ new ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
DTO๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ ๋ฐํ๋ฐ์ ์ ์๋ค. ๋ค๋ง ์ ์ฒด ํจํค์ง๋ช ์ ๋ค ์ ์ด์ค์ผํ๋ค๋ ๋จ์ ์ด ์๋ค.
* ๋์ค์ ์ฟผ๋ฆฌ๋น๋ (QueryBuilder)๋ฅผ ์ฌ์ฉํ๋ฉด ํจํค์ง๋ช ์ ์ฝ๊ฒ ์ ๋ ฅํ ์ ์๋ค.
SELECT new com.mypackage.UserDTO(m.username, m.age) FROM Member m
List<MemberDTO> result = em.createQuery("SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m")
.getResultList();
๐ ํ์ด์ง API
DB SQL์ ์จ๋ดค๋ค๋ฉด ์๊ฒ ์ง๋ง, ํ์ด์ง ์ฟผ๋ฆฌ๋ ์ธ์ ๋ ๊ณจ์นซ๊ฑฐ๋ฆฌ์๋ค.
-- 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 ?, ?
-- 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_ > ?
๊ทธ๋์ JPA์์๋ ํ์ด์ง์ ๋จ 2๊ฐ๋ก ์ถ์ํํ API๋ฅผ ์ ๊ณตํด์ค๋ค.
๐ JPQL ์กฐ์ธ
๊ฐ๋จํ๋ค.
๋ฌผ๋ก ์กฐ์ธ๋ฌธ์ ์ง์ ์ฌ์ฉํ์ง ์์๋ ์กฐํํ ๋ ์กฐ์ธ์ด ํ์ํ๋ฉด, Join SQL์ด ๋๊ฐ๊ฒ ๋๋ค.
ํ์ง๋ง ๊ฐ๋ฅํ๋ฉด JPQL๋ ๋ช ์์ ์ธ Join๋ฌธ์ ์ฌ์ฉํด์ฃผ์. DB ํ๋ ํ ๋ ๋์๋๊ธฐ๋ํ๊ณ , ๋๋๋ก์ด๋ฉด SQL๊ณผ ๋น์ทํ๊ฒ ๊ตฌ์ฑํ๋๊ฒ ์ข๋ค.
๐ ์ ๊ธฐ๋ฅ - ์กฐ์ธ ON์
(JPA 2.1 + ํ์ด๋ฒ๋ค์ดํธ 5.1)๋ถํฐ ON์ ์ ํ์ฉํ ์ ์๋ค. ์ฐ๊ด ๊ด๊ณ๊ฐ ์๋ ์ธ๋ถ์กฐ์ธ์ด ๊ฐ๋ฅํ๋ค. (JPQL)
๋ค๋ง ๊ทธ ์ดํ ๋ฒ์ ์ ์ฌ์ฉํ๋ ๊ธฐ์ (SpringBoot 1.0 ๋ฒ์ ์์ )์ ๊ฑฐ์ ์์ผ๋ฏ๋ก, ๊ทธ๋ฅ ๊ธฐ๋ณธ๊ธฐ๋ฅ์ด๋ผ๊ณ ์๊ฐํด๋ ์ข๋ค.
๐ ์๋ธ์ฟผ๋ฆฌ
ํฌ๊ฒ ์ด๋ ต์ง ์๋ค.
--ํA ์์์ธ ํ์
select m from Member m
where exists (select t from m.team t where t.name = 'ํA')
--์ ์ฒด ์ํ ๊ฐ๊ฐ์ ์ฌ๊ณ ๋ณด๋ค ์ฃผ๋ฌธ๋์ด ๋ง์ ์ฃผ๋ฌธ๋ค
select o from Order o
where o.orderAmount > ALL (select p.stockAmount from Product p)
--์ด๋ค ํ์ด๋ ํ์ ์์๋ ํ์
select m from Member m
where m.team = ANY (select t from Team t)
๋ค๋ง JPA ์์๋ WHERE, HAVING ์๋ธ์ฟผ๋ฆฌ๋ง ์ ๊ณตํ๊ณ , ํ์ด๋ฒ๋ค์ดํธ์์๋ SELECT ์๋ธ์ฟผ๋ฆฌ๊น์ง ์ง์ํ๋ค.
์ธ๋ผ์ธ ๋ทฐ(FROM ์ ์๋ธ์ฟผ๋ฆฌ)๋ JPQL์์๋ ๋ถ๊ฐ๋ฅํ๋ค
์ด๊ฒ ์๋๋ ์ด์ ๋ ORM ๊ธฐ์ ์ ํ๊ณ..๋ญ ์ด๋ฐ๊ฑด ์๋๊ณ ํ์ด๋ฒ๋ค์ดํธ JPQL Parser๊ฐ ์์ง ์ธ๋ผ์ธ๋ทฐ๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค. SQL ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋๋ฐ ์ด๋ ค์์ด ์์ด์ ๊ทธ๋ฌํ ๋ฏ ํ๋ค. ํ์ด๋ฒ๋ค์ดํธ 6.0์ด ๋์ค๋ฉด ํด๊ฒฐ๋ ์๋ ์๋ค.
๋ง์ฝ ์ธ๋ผ์ธ๋ทฐ๋ฅผ ์กฐ์ธ์ผ๋ก ํ ์๊ฐ ์๋ ์ํฉ์ด๋ผ๋ฉด ์๋์ ๊ฐ์ ๋์์ด ์๋ค.
1. ์กฐ์ธ์ผ๋ก ๋ณ๊ฒฝํ๋ค.
2. ์ฟผ๋ฆฌ๋ฅผ ์ฌ๋ฌ๊ฐ๋ก ๋ถ๋ฆฌํ๋ค.
3. ๊ทธ๋๋ ๋ต์ด ์๋์ค๋ฉด ๋ค์ดํฐ๋ธ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค.
์กฐ์ธ์ ๋ง ๊ทธ๋๋ก ํ ์ด๋ธ 2๊ฐ๋ฅผ ๊ฐ์ ธ์ค๋๊ฑฐ๊ณ , ๋ค์ดํฐ๋ธ๋ ๊ทธ๋ฅ ์ฉ SQL์ ์ฐ๋๊ฑฐ๋ค.
์ฟผ๋ฆฌ๋ฅผ ์ฌ๋ฌ๊ฐ๋ก ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํ์๋ฉด, ์๋์ ๊ฐ์ ์์ ํ ์ด๋ธ์ด ์๋ค๊ณ ์๊ฐํด๋ณด์.
๊ทธ๋ฆฌ๊ณ ์ธ๋ผ์ธ๋ทฐ(From์ ์๋ธ์ฟผ๋ฆฌ)๊ฐ ํ์ํ ๋
-- ํ๋น ๋์ด๊ฐ ๊ฐ์ฅ ๋ง์ ํ์์ ์ ๋ณด(username, age)๋ฅผ ์ถ๋ ฅํ๋ผ
SELECT m.*
FROM member m, (select team_id, max(age) as max_age from member group by team_id) m2
WHERE m.team_id = m2.team_id and m.age = m2.max_age;
์ด๋ ๊ฒ 2๊ฐ๋ก ์ชผ๊ฐ๋ผ๋ ๋ง์ด๋ค. ์กฐ๊ธ ๋ฒ๊ฑฐ๋กญ๊ธด ํ๋ค.
-- 1. ํ๋น max(age)๋ฅผ ๋ฝ์๋. Java ๋ณ์๋ก ๊ฐ์ ์ ์ฅํด๋
select team_id, max(age) as max_age from member m2 group by team_id;
--2. ์ ์ฅํ max(age)๋ฅผ ์ด์ฉํด์ ์ํ๋ ํ์์ ์กฐํํจ.
select m.team_id, m.username, m.age from member m
where (m.team_id = 1 and m.age = 20) or (m.team_id=2 and m.age=30);
๋ค๋ง ์์์ ๋งํ ๊ฒ์ฒ๋ผ, ์ฟผ๋ฆฌ๊ฐ ์ ๋ง ๋ณต์กํด์ JPQL๋ก ๋ง๋ค๊ธฐ ์ด๋ ค์ด ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์๋ค.
๊ทธ๋ ๊ทธ๋ฅ ๋ค์ดํฐ๋ธ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์์ JDBC(SpringJDBCTemplate)๋ฅผ ์ด์ฉํด์ ์ฉ SQL์ ์ฌ์ฉํ๋ฉด ๋๋ค.
์์์ฑ ์ปจํ ์คํธ flush๋ง ์ ์ ํ๊ฒ ํด์ค๋ค๋ฉด, ํฐ ๋ฌธ์ ์์ด ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
๐JPQL ํ์ ํํ
์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ ์ํฐํฐ๋ ์๋ฒ ๋๋ ํ์ ์ ํจํค์ง๋ช ์ ๊ทธ๋๋ก ์ฐ๋ฉด ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์ด์ธ์๋ JPQL ๊ตฌ๋ฌธ์ ์๋์ ๊ฐ์ ๊ธฐ๋ณธํ์ ๋ค์ ์ฌ์ฉํ ์ ์๋ค.
์ฐธ๊ณ ๋ก ์ํฐํฐ ํ์ ์ผ๋ก ์กฐํ๋ ๊ฐ๋ฅํ๋ค.
๐ ์กฐ๊ฑด CASE ์
JPQL์ ๊ฐ๋จํ ์กฐ๊ฑด์ (case when else)๋ฅผ ์ ๊ณตํด์ค๋ค.
์๋์ ๊ฐ์ ํน์ํ ์กฐ๊ฑด์๋ ์ ๊ณตํด์ค๋ค.
์ด๋ JPA ํ์คํจ์๋ผ์, ๋ชจ๋ DB์์ ๋์ผํ๊ฒ ๋์์ ๋ณด์ฅํ๋ค.
๊ทธ ์ธ ์๋์ ๊ฐ์ JPQL ํ์ค ํจ์๋ค์ด ์กด์ฌํ๋ค. ์๊ฐ๋ณด๋ค ๋ง์ด ์๋ค.
๊ทธ ์ธ ํน์ DB์์๋ง ์ ๊ณตํ๋ ํจ์๋ ์๋์ ๊ฐ์ด ์ ์ํ ์ ์๋ค.
๋ฌผ๋ก ๊ทธ๋ฅ ๋๋๊ฑด์๋๊ณ , ํด๋น DB์ Dialect๋ฅผ ๋ฑ๋กํด์ฃผ์ด์ผํ๋๋ฐ ์ด๋ฏธ ๋ค์ํ ์ข ๋ฅ์ Dialect๋ฅผ ํ์ด๋ฒ๋ค์ดํธ์์ ์ ๊ณตํด์ฃผ๋ฏ๋ก ํธํ๊ฒ ์ธ ์ ์๋ค. ๋ง์ฝ ๋ด๊ฐ ์ฐ๋ DB๊ฐ ์๋ค๋ฉด ์ง์ Dialect๋ฅผ ๋ฑ๋กํด์ผํ๋ค. ๋ฌผ๋ก ๊ทธ๋ด ์ผ์ ์์ง๋ง
๐ ๊ฒฝ๋ก ํํ์
๊ฒฝ๋ก ํํ์์ ๊ฐ์ฒด ๊ทธ๋ํํ์ (member.name)์ ์๋ฏธํ๋ค.
SQL์๋ ์ด๋ฐ๊ฒ ์์ผ๋๊น, ์ด๋ฐ ๊ฐ์ฒด ๊ทธ๋ํ ํ์์ JPQL ์์ ์ ๊ณตํ๋ ๊ฒฝ๋กํํ์์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์ํ, ๋จ์ผ ์ฐ๊ด, ์ปฌ๋ ์ ์ฐ๊ด์ ๊ตณ์ด ๊ตฌ๋ถํ๋ ์ด์ ๋, JPA์ ๋์์ด ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์ด๋ค.
๊ฐ๊ฐ์ ๋์์ ์๋์ ๊ฐ๋ค.
๊ฒฐ๋ก ๋ถํฐ ์ด์ผ๊ธฐ ํ์๋ฉด, ๋ฌต์์ ์กฐ์ธ์ด ๋ฐ์ํ์ง ์๋๋ก JPQL์ ๋ง๋ค์.
m.team.name ์ฒ๋ผ ๊ฐ์ฒด ๊ทธ๋ํ ํ์์ด ๊ฐ๋ฅํ๋ค.
์ปฌ๋ ์ ์ฐ๊ด๊ด๊ณ๋ ํ์์ ์๋์ง๋ง, ๋ด๋ถ์์ ์กฐ์ธ์ ๊ทธ๋๋ก ๋ฐ์ํ๋ค.
๊ทธ๋ฅ ๊ฐ์ฒด๊ฐ ์ปฌ๋ ์ (List) ์ ๋ค์ด๊ฐ๋๊น, List.size() ์ด๋ฐ ๋ฉ์๋๋ฐ์ ํธ์ถ์ด ์๋์ ํ์์ด ์๋๋๊ฑฐ์ง [๋จ์ผ ๊ฐ ์ฐ๊ด๊ฒฝ๋ก]์ ๋๊ฐ์ด ์กฐ์ธ์ ๋ฐ์ํ๋ค. ๋ง์ฝ as๋ก ๋ณ์นญ์ ์ฃผ๋ฉด ํ์๊ฐ๋ฅํ๋ค.
์ฆ JPQL์์๋ ์๋ฌด์ผ์ด ์๋ ๊ฒ ๊ฐ์ง๋ง, ์๋ฌด๋ ๋ชจ๋ฅด๊ฒ SQL ์ฑ๋ฅ์ด ๊ตฌ๋ ค์ง๋ค. ๋งค์ฐ ์กฐ์ฌ์ค๋ฝ๊ฒ ์ฌ์ฉํด์ผํ๋ค.
๊ทธ๋ฅ ๋ฌต์์ ์กฐ์ธ์ ์ฐ์ง๋ง๊ณ , ๋ด๋ถ์์ ์กฐ์ธ์ด ๋ฐ์ํ๋ค๋ฉด JPQL join ๊ตฌ๋ฌธ์ ์ด์ฉํด์ ๋ช ์์ ์ผ๋ก ๋ฐ๊ฟ์ฃผ์.
๋ง์ฝ school.class.students.student.address.city ์ด๋ ๊ฒ ํ์์ ํด๋ฒ๋ฆฌ๋ฉด
SQL ์ด๋์กฐ์ธ์ด 7๋ฒ ๋ฐ์ํ๋ค. ๋๋ฉ์ธ ์ค๊ณ, ์ฑ๋ฅ ๋ ๋ค ๋์ฐํ๋ค.
๐ join fetch(ํจ์น์กฐ์ธ)
์ฐธ๊ณ ๋ก DB์๋ ํจ์น์กฐ์ธ์ด๋ผ๋ ๊ฐ๋ ์ด ์๋ค.
JPA์์ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ผ๋ก, ์ฐ๊ด๋ ์ํฐํฐ๋ ์ปฌ๋ ์ ์ SQLํ๋ฐฉ์ฟผ๋ฆฌ๋ก ๋ฐ๊พธ๋ ๊ธฐ๋ฅ์ด๋ค.
์ฐธ๊ณ ๋ก Inner Join์ผ๋ก ๊ฐ์ ธ์ค๊ฒ ๋๋ค.
String jpql = "select m from Member m join fetch m.team";
List<Member> members = em.createQuery(jpql, Member.class)
.getResultList();
for (Member member : members) {
//ํ์น ์กฐ์ธ์ผ๋ก ํ์๊ณผ ํ์ ํจ๊ป ์กฐํํด์ ์ง์ฐ ๋ก๋ฉX
System.out.println("username = " + member.getUsername() + ", " +
"teamName = " + member.getTeam().name());
}
์ผ๋๋ค (@OneToMany)๋ ๋ง์ฐฌ๊ฐ์ง.
๋ค๋ง ์ด ๊ฒฝ์ฐ N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฑธ ์์ง๋ง์. ์ด๋ Lazy๋ก ์กฐํํด๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ค. (Lazy๋ ์ค ์ฌ์ฉ๊น์ง ์กฐํ ํ์ด๋ฐ์ ๋ฆ์ถฐ์ค ๋ฟ, N+1์ ์ต์ ํ์์ผ์ ์ ๊ฑฐํ๋๊ฒ ์๋๋ค)
๐ ํจ์น์กฐ์ธ๊ณผ Distinct
SQL์ DISTINCT๋ ์ค๋ณต์ ์ ๊ฑฐํ๋ ๋ช ๋ น์ด๋ค.
ํ์ง๋ง ์ผ๋๋ค(@OneToMany)๊ด๊ณ์์๋ ์ ๊ทธ๋ฆผ์ฒ๋ผ ์ค๋ณต ๋ ์ฝ๋(ํA-ํ์1, ํA-ํ์2, ํA-ํ์3...)๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์, ํจ์น์กฐ์ธ๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด DISTINCT๊ฐ ์ ๋๋ก ๋์ํ์ง ์๋๋ค. ๋ค๋์ผ ๊ด๊ณ์์๋ ์ค๋ณต์ด ๋ฐ์ํ ์ผ์ด ์๋ค.
๋ค๋ง JPA์์ ์ํฐํฐ๋ฅผ ์กฐํํ๋ฉด ์ ๊ฑฐ๊ฐ ๋์ด์๋๋ฐ, ์ด๋ ์ดํ๋ฆฌ์ผ์ด์ (JPA)์์ ์ค๋ณต๋ ์ํฐํฐ๋ฅผ ์ ๊ฑฐํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ญ ๋ณ ์๊ฐ์์ด ์ฌ์ฉํ ์๋ ์๊ฒ ์ง๋ง, JPA์์ ํ๋ฒ ๋ ์ฒ๋ฆฌํ๊ธฐ์ ์ค์ SQL ์ฟผ๋ฆฌ๋ฌธ์ ๋ค๋ฅด๋ค๋๊ฑธ ์ธ์งํ๊ณ ์์.
๐ ํจ์น์กฐ์ธ์ ํ๊ณ
ํจ์น์กฐ์ธ์ ๋ง ๊ทธ๋๋ก ๊ฐ์ฒด ๊ทธ๋ํ์ ์๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ํ๋ฐฉ์ ๊ฐ์ ธ์ค๋ ์ฟผ๋ฆฌ๋ค.
๋ง์ฝ ๋ณ์นญ(m.username)์ ์ฃผ๊ณ ์ผ๋ถ๋ง ์ฌ์ฉํ๋ฉด, ๋๋จธ์ง ๋ฐ์ดํฐ์ ๋ํด์ JPA๊ฐ ์ด์ํ๊ฒ ๋์ํ ์ ์๋ค.
๋ณ์นญ๊ณผ ๊ฐ์ ์ด์ ๋ก ํ์ด์ง API๋ฅผ ์ฌ์ฉํด์๋ ์๋๋ค. ๋ฌผ๋ก ๋ฐ์ดํฐ ๋ปฅํ๊ธฐ๊ฐ ๋์ง์๋ ManyToOne์ ์๊ด์๋ค.
๋ฐ์ดํฐ๊ฐ ๋ปฅํ๊ธฐ ๋์ด ํ์ด์ง์ด ์ด์ํ๊ฒ ๋ ์ ์๋ค.
๋ง์ฝ ๊ทธ๋ฐ๊ฒ ํ์ํ๋ค๋ฉด ๋ค๋์ผ(@ManyToOne)์์ ๋ณ๋์ ์ฟผ๋ฆฌ๋ก ์ง์ ๊ฐ์ ธ์ค๋๋ก ํ์.
์ฌ์ฉํ์ง ์๋ ๋๋จธ์ง ๋ฐ์ดํฐ๊ฐ ์ญ์ ๋๊ฑฐ๋ ์ ๋๋ก ๋ฐ์๋์ง ์์ ์ ์๋ค. (์ ํฉ์ฑ ์ด์) ํจ์น ์กฐ์ธ์ ๊ฐ์ฒด ๊ทธ๋ํ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ถ ๋ค ๊ฐ์ ธ์ค๋๋ก ์ค๊ณ๋์์ผ๋ฏ๋ก, ์ด๋ฌํ ์ค๋ฅ๋ฅผ ๋ณด์ฅํด์ฃผ์ง ์๋๋ค.
โ ๋ค๋ง ์๋์ ๊ฐ์ ๊ฒฝ์ฐ, ์กฐ์ธ ํจ์น๋ฅผ ์ ์ ๋ ๋ณ์นญ์ ์ฌ์ฉํ๊ธฐ๋ ํ๋ค.
๋ง์ง๋ง์ผ๋ก ๋ ์ด์์ ์ปฌ๋ ์ ์ ํจ์น์กฐ์ธํ๋ฉด ์๋๋ค. ์ผ๋๋ค(@OneToMany)๋ ๋ฐ์ดํฐ๊ฐ ๋ปฅํ๊ธฐ ๋๋๋ฐ, (@OneToManyToMany) ์ด๋ ๊ฒ ํด๋ฒ๋ฆฌ๋ฉด ์ ํฉ์ฑ์ด ๊นจ์ง ์ ์๋ค.
๐ ํจ์น์กฐ์ธ์ ํน์ง๊ณผ ํ๊ณ
๐ ๋ฒํฌ ์ฐ์ฐ (์์ ,์ญ์ )
JPA๋ ์ปค๋ฐ ์์ ์ Entity์ ๋ณ๊ฒฝ์ ๊ฐ์งํด์ ์ ์ ํ ์ฟผ๋ฆฌ๋ฅผ ๋ฐ์์ํจ๋ค.
ํ์ง๋ง ์์ ์ ํ๋ค๋ณด๋ฉด ๋ฒํฌ์ฑ ์ฟผ๋ฆฌ(ex ์ฌ๊ณ ๊ฐ 10๊ฐ ๋ฏธ๋ง์ธ ์ํ ์ ์ฒด์ ๊ฐ๊ฒฉ์ 20% ์์น) ์์ ์ ํ ๋๋ ์๋ค.
SQL๋ก๋ ๊ฐ๋จํ ์์ ์ด์ง๋ง JPA ๋ณ๊ฒฝ๊ฐ์ง๋ก๋ ๋ฆฌ์์ค๋ ๋ง์ด ์ก์๋จน๊ณ , ์ฟผ๋ฆฌ๊ฐ ๋ณ๊ฒฝ๋ ๊ฐ์๋งํผ ๋๊ฐ ์ ์๋ค.
๊ทธ๋์ ์์ JPA์์๋ ์ด๋ฌํ ์์ ์ ์ํด executeUpdate() ๋ผ๋ ๋ฉ์๋๋ฅผ ์ ๊ณตํด์คฌ์๋ค.
- ํด๋น ๋ฉ์๋๋ ์์์ฑ ์ปจํ
์คํธ๋ฅผ ๋ฌด์ํ๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฐ๋ค.
= ๋ฒํฌ์ฐ์ฐ์ ๋ณ๊ฒฝ๊ฐ์ง๊ฐ ์๋ํ์ง ์๋๋ค. ์ฌ์ฉํ๋ฉด ์์์ฑ ์ปจํ ์คํธ์ Database์ ์ ํฉ์ฑ์ด ๊นจ์ง๋ค. - ๊ทธ๋์ ๋ฒํฌ์ฐ์ฐ ์ดํ์ ์์์ฑ ์ปจํ
์คํธ๋ฅผ ์ด๊ธฐํ(em.clear)ํ๊ณ ๋ค๋ฅธ ์์
์ ํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
๊ฐ๋ฅํ๋ฉด ๋ฒํฌ์ฐ์ฐ์ ๋จผ์ ํ๊ณ em.clear()๋ฅผ ํ๋๋ก ํ์.
์์์ฑ ์ปจํ ์คํธ๋ฅผ ์์ ํ ๋น์๋ฒ๋ฆฌ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ค์ ์กฐํํ๊ธฐ ๋๋ฌธ์ ์ ํฉ์ฑ์ด ๊นจ์ง์ง์๋๋ค.
์ฐธ๊ณ ๋ก JPA ๋ Update, Delete ์ฟผ๋ฆฌ๋ง ์ง์ํ๊ณ , ํ์ด๋ฒ๋ค์ดํธ์์๋ select (insert into select๋ฌธ)๊น์ง ์ถ๊ฐ ์ง์ํ๋ค.
// Update ๋ฒํฌ์ฐ์ฐ
String query = "update Product p "+
"set p.price = p.price * 1.1 " +
"where p.stockAmount < :stockAmount";
int resultCount = em.createQuery(query)
.setParameter("stockAmount", 10)
.executeUpdate();
// Delete ๋ฒํฌ์ฐ์ฐ. (Select ๋ฒํฌ์ฐ์ฐ์ JPA ์คํ์๋ ์๊ณ , ํ์ด๋ฒ๋ค์ดํธ๋ง ์ง์ํ๋ค.)
int deletedCount = em.createQuery("DELETE FROM Country").executeUpdate();
์ฐธ๊ณ ๋ก ํ์ด๋ฒ๋ค์ดํธ๋ง ์ง์ํ๋ ๋ฒํฌ์ฑ insert into select๋ ์๋์ ๊ฐ์ ๋ฐฐ์น ์ฟผ๋ฆฌ๋ฅผ ๋งํ๋ค.
// Batch
INSERT INTO table1 (col1, col2) VALUES
(val11, val12),
(val21, val22),
(val31, val32);
'๐ฑBackend > JDBC & JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Data JPA (0) | 2022.01.31 |
---|---|
JPA ์ฑ๋ฅ ๊ฐ์ ํ (0) | 2022.01.22 |
JPA #9 ๊ฐ ํ์ , ์ปฌ๋ ์ , ์๋ฒ ๋๋ ํ์ (0) | 2021.11.09 |
JPA #8 ํ๋ก์์ ์ง์ฐ๋ก๋ฉ (join fetch) (0) | 2021.11.09 |
JPA #7 ๊ณ ๊ธ ๋งคํ (์์ ๊ด๊ณ) (0) | 2021.11.09 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev