๐ŸƒSpring JPA์˜ ๋„์ž…

Spring JPA

2 minute read

๋„์ž… - ๊ธฐ์กด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ 

  • ๊ฐ์ฒด์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ๋ถˆ์ผ์น˜
  • ๊ฐ์ฒด์ง€ํ–ฅ์ด ์•„๋ฌด๋ฆฌ ์ข‹์•„๋„ ์˜๊ตฌ์ ์œผ๋กœ ๋ณด๊ด€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ˜„์‹ค์ ์œผ๋กœ๋А ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • SQL์— ์˜์กด์ ์ธ ๊ฐœ๋ฐœ์„ ํ”ผํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

  • ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋„ ์ƒ์†๊ด€๊ณ„์™€ ์œ ์‚ฌํ•œ ๊ตฌ์กฐ๊ฐ€ ์žˆ์ง€๋งŒ, ๋ชจ๋“  ์ฟผ๋ฆฌ์— ์กฐ์ธ์„ ๋„ฃ์–ด์„œ ๊ตฌํ˜„ํ•  ๊ฒƒ์ธ๊ฐ€?
  • ๊ฐ์ฒด ๋‚ด๋ถ€์˜ Has-A ๊ด€๊ณ„๋ฅผ ๊ณ„์ธต์ ์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜๋Š” ์—†์„๊นŒ?
  • ๊ฒฐ๋ก ์ ์œผ๋กœ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋„ ์ž๋ฐ” ์ปฌ๋ ‰์…˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†์„๊นŒ?

  • ๊ทธ๋ฆฌ๊ณ  ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์„๊นŒ?
    ```java
    class MemberDAO {
    public Member getMember(String memberId) {
    String sql = โ€œSELECT * FROM MEMBER WHERE MEMBER_ID = ?โ€;
    โ€ฆ
    //JDBC API, SQL ์‹คํ–‰
    return new Member(โ€ฆ);
    }
    }

String memberId = โ€œ100โ€;
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2; //๋‹ค๋ฅด๋‹ค.

  
์œ„์ฒ˜๋Ÿผ ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ์–ป์–ด์˜จ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ์ง€๋งŒ, ์šฐ๋ฆฌ๊ฐ€ ์“ฐ๋Š” ์ž๋ฐ” ์ปฌ๋ ‰์…˜์€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์–ป์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.  
  
```java  
String memberId = "100";  
 Member member1 = list.get(memberId);  
Member member2 = list.get(memberId);  
 member1 == member2; //๊ฐ™๋‹ค.  

์ด๋Ÿฌํ•œ ๋„์ž…๋ฐฐ๊ฒฝ์œผ๋กœ ์ธํ•ด JPA๋ผ๋Š” ๊ธฐ์ˆ ์ด ๋Œ€๋‘๋˜๊ฒŒ ๋œ๋‹ค.

JPA

  • Java Persistence API
  • node.js์˜ TypeORM, django์˜ django ORM์ฒ˜๋Ÿผ ์ž๋ฐ” ์ง„์˜์˜ ORM ๊ธฐ์ˆ  ํ‘œ์ค€์ด๋‹ค.
  • Object-relational mapping(๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘)
  • ์ข‹์€ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์ด ๊ทธ๋ ‡๋“ฏ ๊ธฐ์กด์˜ JDBC๋ฅผ ์ž˜ wrappingํ•ด์„œ ์ข‹์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

History

  • ์Šคํ”„๋ง์˜ ๋ชจํƒœ์ด๊ธฐ๋„ ํ•œ EJB(์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ž๋ฐ” ๋นˆ)์—์„œ ๋ถˆํŽธํ•จ์„ ๋А๋‚€ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋ผ๋Š” ์˜คํ”ˆ์†Œ์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜์˜€๋‹ค.
  • ๋Œ€์ค‘์ ์œผ๋กœ ์—„์ฒญ๋‚˜๊ฒŒ ํฅํ–‰ํ•˜์—ฌ ์‚ฌ์‹ค์ƒ์˜ ํ‘œ์ค€์ด ๋˜์ž ์ž๋ฐ” ์ง„์˜์—์„œ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋ฅผ ์ˆ˜์šฉํ•˜์—ฌ JPA๋ผ๋Š” ํ‘œ์ค€์„ ์ •์˜ํ•˜์˜€๋‹ค.
  • ์Šคํ”„๋ง๊ณผ๋Š” ๋‹ค๋ฅธ ์–‘์ƒ์œผ๋กœ ์Šคํ”„๋ง์€ ์‚ฌ์‹ค์ƒ ํ‘œ์ค€์ด์ง€๋งŒ ์•„์ง ์ž๋ฐ”์ง„์˜์—์„œ ํ‘œ์ค€์€ ์•„๋‹ˆ๋‹ค.
  • JPA๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ชจ์Œ์œผ๋กœ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋Š” ๊ทธ ๊ตฌํ˜„์ฒด์ด๋‹ค. ์‚ฌ์‹ค ๊ตฌํ˜„์ฒด๊ฐ€ ๋” ๋จผ์ € ๋‚˜์˜ค๊ธฐ๋Š” ํ–ˆ์ง€๋งŒโ€ฆ
  • Hibernate, EclipseLink, DataNucleus๊ฐ™์€ ๊ตฌํ˜„์ฒด๋“ค์ด ์žˆ๋‹ค.

ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ

  • ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ JPA๊ฐ€ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.
  • ํ…Œ์ด๋ธ”์˜ ์Šˆํผํƒ€์ž…, ์„œ๋ธŒํƒ€์ž… ๊ด€๊ณ„๋ฅผ ๊ฐ์ฒด์˜ ์ƒ์†๊ด€๊ณ„์™€ ๋งคํ•‘ํ•˜์—ฌ ๊น”๋”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๋ฌผ๋ก  ๋’ค์—์„œ๋Š” ๋ฐฑ์กฐ์˜ ๋ฐœ์ฒ˜๋Ÿผ ์—„์ฒญ๋‚œ ๋…ธ๊ฐ€๋‹ค๊ฐ€ ๋Œ€์‹  ์ด๋ฃจ์–ด์ง€๊ณ  ์žˆ๋‹ค.
  • Has-A ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ๊ฐ์ฒด๋„ JPA๊ฐ€ ์ฒ˜๋ฆฌํ•ด์ค„ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
    ```java
    member.setTeam(team);
    jpa.persist(member);

Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();

  
- ์—”ํ‹ฐํ‹ฐ์˜ ์‹ ๋ขฐ์„ฑ์ด ์ƒ๊ฒผ๋‹ค.  
```java  
String memberId = "100";  
 Member member1 = jpa.find(Member.class, memberId);  
Member member2 = jpa.find(Member.class, memberId);  
 member1 == member2; //๊ฐ™๋‹ค.  

JPA์—์„œ ์ƒ๊ธด ์ถ”๊ฐ€์ ์ธ ์žฅ์ 

  • 1์ฐจ ์บ์‹œ์™€ ๋™์ผ์„ฑ(identity) ๋ณด์žฅ
  • ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ(transactional write-behind)
  • ์ง€์—ฐ ๋กœ๋”ฉ(Lazy Loading)

JPA๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด์ž

Dialect(๋ฐฉ์–ธ)

  • ์„ธํŒ…(persistence.xml)์‹œ ํ•„์š”ํ•˜๋‹ค. ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋งˆ๋‹ค ๋น„์Šทํ•œ๋“ฏ ๋‹ค๋ฅธ SQL ๋ฌธ๋ฒ•์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์„ค์ •ํ•ด์ฃผ๊ฒŒ ๋˜๋ฉด ์•Œ์•„์„œ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๊ฐ€ ๋ฒˆ์—ญํ•ด์ค€๋‹ค.
  • ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•ด์ค€๋‹ค.
    H2 : org.hibernate.dialect.H2Dialect  
    Oracle 10g : org.hibernate.dialect.Oracle10gDialect MySQL : org.hibernate.dialect.MySQL5InnoDBDialect  
    

๊ตฌ๋™๋ฐฉ์‹

  • ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € ํŒฉํ† ๋ฆฌ๋Š” ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์— ์„œ ๊ณต์œ 
  • ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ„์— ๊ณต์œ X (์‚ฌ์šฉํ•˜๊ณ  ๋ฒ„๋ ค์•ผ ํ•œ๋‹ค).
    => ์œ„ ๋‘๊ฐœ๋Š” Bean์˜ ํŠน์„ฑ์ด๊ธฐ๋„ ํ•˜๋‹ค.
  • JPA์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์€ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์‹คํ–‰

JPA๋กœ ๋ชจ๋‘ ๋‹ค ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?

  • ์•ˆ๋ ๊ฑด ์—†์ง€๋งŒ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ๊ธฐ์ˆ ๋“ค์ด ํ•„์š”ํ•˜๋‹ค.
  • JPQL : SQL๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์†Œ ์•„์‰ฝ์ง€๋งŒ ๊ทธ๋ž˜๋„ ์ƒ SQL๋ณด๋‹ค ๋งŽ์€ ์ด์ ์ด ์žˆ๋‹ค.
  • QueryDSL : ์•„์ฃผ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋„ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.