JiwonDev

JPA #3 ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

by JiwonDev

๐Ÿ“Œ SQL ๋ฐฉ์–ธ (Dialect)

๊ฐ ํšŒ์‚ฌ๋งˆ๋‹ค ๋‹ค๋ฅธ SQL ๋ฌธ๋ฒ•์€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ? (Limit, ROWNUM)

org.hibernate.dialect ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. JPA์™€ DB์˜ ์˜์กด์„ฑ์„ ์ตœ์†Œํ™” ํ• ์ˆ˜ ์žˆ๋‹ค.

Dialect์€ ํ•œ๊ธ€๋กœ ๋ฐฉ์–ธ, ์‚ฌํˆฌ๋ฆฌ๋ผ๋Š” ๋œป.

 

์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ„์ „๋งˆ๋‹ค ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” Hibernate ๋ฒ„์ „์ด ๋‹ค๋ฅด๋ฏ€๋กœ, ๋ฒ„์ „์„ ์„ค์ •ํ•  ๋•Œ ์ฃผ์˜ํ•˜์ž.

Spring ์‚ฌ์ดํŠธ - Projects - Spring Boot - Learn ํƒญ์œผ๋กœ ๋“ค์–ด๊ฐ€์„œ, Ref Docs์—์„œ ๋ฒ„์ „(Dependency)์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Gradle, Maven ์„ค์ • ๋ฐฉ๋ฒ•

๋”๋ณด๊ธฐ

Gradle์€ application.yml ์„ค์ •ํŒŒ์ผ์—์„œ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://...์ƒ๋žต
    username: ์œ ์ €๋ช…
    password: ๋น„๋ฐ€๋ฒˆํ˜ธ
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    hibernate:
      dialect: org.hibernate.dialect.MySQL5InnoDBDialect // ์ด๋Ÿฐ ์‹์œผ๋กœ ์ถ”๊ฐ€๊ฐ€๋Šฅ
      ddl-auto: none
    properties:
      hibernate:
        format_sql: true

  data:
    web:
      pageable:
        default-page-size: 10

 

Maven์€ .../resources/META_INF/persistence.xml ์„ ๋งŒ๋“ค์–ด์„œ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
  xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">

  <!-- ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„ -->
  <persistence-unit name="hello">
    <properties>
      <!-- ํ•„์ˆ˜ ์†์„ฑ -->
      <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
      <property name="javax.persistence.jdbc.user" value="sa"/>
      <property name="javax.persistence.jdbc.password" value=""/>
      <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
      <!--  H2 DB์˜ Dialect ์„ค์ • -->
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

      <!-- ์˜ต์…˜ -->
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.use_sql_comments" value="true"/>
      <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
    </properties>
  </persistence-unit>
</persistence>

 

 

๐Ÿ“Œ JPA ๊ตฌ๋™ ๋ฐฉ์‹

EntityManager๋Š” ์Šค๋ ˆ๋“œ๊ฐ„ ๊ณต์œ ํ•ด์„  ์•ˆ๋œ๋‹ค. (์‚ฌ์šฉํ•˜๊ณ  ๋ฐ˜๋‚ฉ)

์Šคํ”„๋ง ์—†์ด JPA๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•˜๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.

public final class MemberService {

    public static void main(String[] args) {
        /* ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘ํ•  ๋•Œ Factory ์ƒ์„ฑํ•œ๋‹ค. */
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("hello");

        // ๐Ÿ’ญ 1. ์Šค๋ ˆ๋“œ์—์„œ ์‚ฌ์šฉํ•  EntityManager ๋ฅผ Factory ๋กœ ์ƒ์„ฑํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜์„ ๋งŒ๋“ ๋‹ค.
        EntityManager entityManager = factory.createEntityManager();
        EntityTransaction tx = entityManager.getTransaction();

        // ๐Ÿ’ญ 2. JPA๋ฅผ ์ด์šฉํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์€ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ๋งŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.
        try {
            Member member = new Member();
            member.setId(2L);
            member.setName("Kim");

            entityManager.persist(member);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            // ๐Ÿ’ญ 3. ์‚ฌ์šฉ์ด ๋๋‚œ EntityManager ๋ฐ˜๋‚ฉํ•œ๋‹ค.
            entityManager.close();
        }

        /* ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒํ•  ๋•Œ ํ•„์š”์—†์–ด์ง„ Factory ๋ฐ˜ํ™˜ํ•œ๋‹ค. */
        factory.close();
    }
}

 

์ •๋ง ์ž๋ฐ” ์ปฌ๋ ‰์…˜์„ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ DB๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

๋‹จ์ˆœํ•œ ํŽธ์˜๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋ผ, JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด commitํ•˜๋Š” ์‹œ์ ์— ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์„ ๊ฐ์ง€ํ•˜์—ฌ SQL ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

try {
    Member findMember = entityManager.find(Member.class, 1L);
    findMember.setName("new_Name"); // ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

    // entityManager.persist(findMember); โžก ์ €์žฅํ•˜์ง€ ์•Š์•„๋„ ์—…๋ฐ์ดํŠธ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์„œ ๋ฐ˜์˜๋จ.
	    
    tx.commit();
} catch (Exception e) { ... }

 

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, EntityManager๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค Connection์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋œ๋‹ค.

์ฆ‰ ์ ˆ๋Œ€๋กœ EntityManager๋ฅผ ๊ณต์œ ํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์—์„œ ์‚ฌ์šฉํ•˜๊ณ , ์‚ฌ์šฉ์ด ๋๋‚˜๋ฉด ๋ฐ˜๋‚ฉํ•ด์•ผํ•œ๋‹ค.

๊ทธ ์ด์œ ๋Š” ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„๋กœ EntityManager๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ DB ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”๊ฐ€ ๊นจ์ง€๊ฒŒ ๋œ๋‹ค. ์ปค๋ฐ‹์ด ๋œ ์ดํ›„์—๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ๋ฐ˜๋‚ฉํ–ˆ๋‹ค๊ฐ€ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

 

๐Ÿ“Œ ๋ณต์žกํ•œ ์กฐํšŒ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜์ฃ ?

๋‹จ์ˆœํžˆ ์ปฌ๋ ‰์…˜์ฒ˜๋Ÿผ ๊บผ๋‚ด๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณต์žกํ•œ ์กฐ๊ฑด์ด ์žˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ๊นŒ?

  • ID๊ฐ€ 2์ด์ƒ์ด๊ณ , ์ด๋ฆ„์ด KIM์ธ ํšŒ์›๋งŒ ๊ฒ€์ƒ‰
  • ์ „์ฒด ํšŒ์›์ค‘ ์ด๋ฆ„์ˆœ์œผ๋กœ 100๋ช…๋งŒ ๊ฒ€์ƒ‰

์ด๋ฅผ ์œ„ํ•ด์„œ JPQL์ด๋ผ๋Š” ๋ฌธ๋ฒ•์ด ์ œ๊ณต๋œ๋‹ค. ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ์ ์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

try {
    List<Member> result = entityManager.createQuery("select m from Member", Member.class)
        .getResultList();

    tx.commit();
} catch (Exception e) {

๋‹ค๋งŒ ์ค‘์š”ํ•œ ๊ฒƒ์€ JPQL์„ ์ด์šฉํ•˜์—ฌ ์ ์€ select m from Member๋Š” DB ํ…Œ์ด๋ธ”์— ์š”์ฒญํ•˜๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๊ฐ์ฒด์ง€ํ–ฅ SQL ๋ฌธ๋ฒ•์ด๋‹ค. ์ฆ‰ ์˜๋ฏธ ๊ทธ๋Œ€๋กœ [ Member ๊ฐ์ฒด ] ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฌธ๋ฒ•์ด๊ณ  ์‹ค์ œ SQL์€ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.

์‹ค์ œ ๊ฒฐ๊ณผ๋„ ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ, [ Member ๊ฐ์ฒด ] ๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.

JPA๋Š” ๊ฐ์ฒด(Entity)๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ œ๊ณตํ•ด์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค.

๋ชจ๋“  DB ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๊ฒ€์ƒ‰ํ•˜๋Š”๊ฑด ์ƒ๋‹นํžˆ ๋น„ํšจ์œจ์ ์ด๊ณ , ์‚ฌ์‹ค์ƒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๊ทธ๋ž˜์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ DB์— ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•ด์„œ JPQL์ด๋ผ๋Š” ๊ฐ์ฒด ์ „์šฉ SQL๋ฌธ์„ ์ถ”๊ฐ€๋กœ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

๋‹ค๋งŒ ์‚ฌ์šฉ๋ฒ•์€ SQL ๋ฌธ๋ฒ•๊ณผ ๊ฑฐ์˜ ์œ ์‚ฌํ•˜๋‹ค. SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN ์ง€์›

 

 

๐Ÿ“Œ JPA์˜ ๋น„๋ฐ€, EntityManager (์˜์†์„ฑ ์ปจํ…์ŠคํŠธ)

JPA๋ฅผ ์กฐ๊ธˆ์ด๋ผ๋„ ๊ณต๋ถ€ํ•ด๋ดค๋‹ค๋ฉด ์•„๋ž˜์˜ ๋‹จ์–ด๋ฅผ ์—„์ฒญ ๋งŽ์ด ๋“ค์–ด๋ดค์„ ๊ฒƒ์ด๋‹ค.

Persistence Context (์˜์†์„ฑ ์ปจํ…์ŠคํŠธ)
- ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜๊ตฌ ์ €์žฅ ํ•˜๋Š” ํ™˜๊ฒฝ.
- ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊บผ๋‚ด์˜จ ๊ฐ์ฒด๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

์‹ค์ œ๋กœ JPA์—์„œ ์ €์žฅํ•  ๋•Œ save() ๋ผ๋Š” ์ด๋ฆ„ ๋Œ€์‹ , persist() ๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ตณ์ด ํ—ท๊ฐˆ๋ฆฌ๊ฒŒ ์™œ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์—ˆ์„๊นŒ?

 

@ EntityManager.persist( ~ )

์‚ฌ์‹ค save ๋Œ€์‹  persist ๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š” ๊ฐ„๋‹จํ•˜๋‹ค.

์‹ค์ œ ๋™์ž‘์ด ๊ฐ์ฒด๋ฅผ DB์— ์ €์žฅํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ(=persist)ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด์ž.

try {
    // ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ์ƒํƒœ(๋น„์˜์†) 
    Member member = new Member();
    member.setId("member1");
    member.setUsername("ํšŒ์›1");
	
    // ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•œ ์ƒํƒœ (์˜์†)
    entityManager.persist(member)
    
    tx.commit();
} catch (Exception e) {
    tx.rollback();

๋น„์˜์†(new ๋˜๋Š” transient) , ์˜์†(managed)

 

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด em.persist()๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ, DB์— ์ €์žฅ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์˜€๋‹ค.

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ํ™•์ธํ•˜๋ฉด em.persist()๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(EntityManager)์— ์žˆ์„ ๋ฟ, ์•„์ง DB์— ์ €์žฅ๋œ๊ฒŒ ์•„๋‹ˆ๋‹ค.

 

 

@ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ == EntityManager ์ธ ๊ฑด๊ฐ€์š”?

์•„๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ๋Š” EntityManager๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด EntityManager์— ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ, ๋น„์˜์† ์ƒํƒœ(=์ค€์˜์†) ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.

์ค€์˜์†์€ ๋งˆ์ง€๋ง‰์— ์ถ”๊ฐ€๋กœ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

 

์ฐธ๊ณ ๋กœ ์˜ˆ์ œ์—์„œ๋Š” EntityManager๋‹น ๊ณ ์œ ํ•œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ์ง€๋งŒ, ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋“ฑ์„ ์‚ฌ์šฉํ•  ๋–„์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ EntityManager๊ฐ€ ํ•˜๋‚˜์˜ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. 

 

์ด๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•œ๋‹ค๊ธฐ ๋ณด๋‹ค๋Š”,

ํ•œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์ด ํ˜ธ์ถœ๋˜๋Š” ์‹คํ–‰ ๊ตฌ์กฐ, ์˜ˆ๋ฅผ ๋“ค์–ด Application โžก Service โžก  Repository ์™€ ๊ฐ™์€ ๊ฒฝ์šฐ EntityManager๋ฅผ ๊ณ„์† ๊ณต์œ ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ƒˆ๋กœ์šด EntityManager๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋งŒ ํ•˜๋‚˜์˜ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•œ๋‹ค๋Š” ๋ง์ด๋‹ค. ์ง€๊ธˆ์€ ์ดํ•ดํ•  ํ•„์š”์—†์œผ๋‹ˆ ์•Œ์•„๋งŒ๋‘๊ณ  ๋„˜์–ด๊ฐ€๋„๋ก ํ•˜์ž.

 

 

@ ๊ท€์ฐฎ๊ฒŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฑฐ์น˜๋Š” ์ด์œ ๊ฐ€ ๋ญ์ฃ ?

DB์— ๋ฐ”๋กœ ์ „์†กํ•˜์ง€์•Š๊ณ , ์ค‘๊ฐ„์— ๋ฒ„ํผ์ฒ˜๋Ÿผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ด์šฉํ•˜๋Š” ์ด์œ ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • DB๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  1์ฐจ ์บ์‹œ์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉ๊ฐ€๋Šฅ
  • ๋™์ผ์„ฑ (identity) ๋ณด์žฅ
  • ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ (tx write-behind)
  • ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ํ†ตํ•œ ์ตœ์ ํ™” (Dirty Checking)
  • ์ง€์—ฐ ๋กœ๋”ฉ ์ง€์› (Lazy Loading)

 

๐Ÿ“Œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ํŠน์ง•

@ 1์ฐจ ์บ์‹œ ์ œ๊ณต

EntityManager๋ฅผ ์ด์šฉํ•˜๋ฉด DB๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ , ์ค‘๊ฐ„์— ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ ํ•œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์บ์‹œ(1์ฐจ)๋ผ์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์—„์ฒญ ๋ณต์žกํ•œ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด, ๋ณ„ ์ฐจ์ด์—†๋‹ค.

๊ณ ๊ฐ์ด 10๋ช…์ด๋ฉด 10๊ฐœ์˜ 1์ฐจ ์บ์‹œ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋Š”๊ฑฐ๋‹ˆ๊นŒ. ๊ทธ๋ƒฅ ๊ตฌ์กฐ์ƒ ์–ป๋Š” ์†Œ์†Œํ•œ ์ด๋“์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

ํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์žฌ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, DB๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ฐ”๋กœ ๊บผ๋‚ด์˜จ๋‹ค.

์ฆ‰ ์œ„์™€ ๊ฐ™์€ ๊ฒฝ์šฐ, DB์— Select ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ€์ง€ ์•Š๋Š”๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ DB๋ฅผ ์‚ฌ์šฉํ•œ ์ ์ด ์—†์œผ๋‹ˆ๊นŒ.

 

 

@ ์˜์†๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๋™์ผ์„ฑ ๋ณด์žฅ

JPA์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์กฐํšŒํ•˜๋”๋ผ๋„ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

์ด๋Š” ์ •๋ง ํฐ ์ฐจ์ด์ธ๊ฒŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ์„ 3. REPEATABLE READ๋กœ ํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ง„๋‹ค.

์•ฑ (Java)๋‹จ์—์„œ [ํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ช‡ ๋ฒˆ์„ ๋ฐ˜๋ณตํ•ด์„œ ์ฝ์–ด๋„] ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

@ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ ์ œ๊ณต

ํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ, em.persist()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค ํ•˜๋”๋ผ๋„ ๋ฐ”๋กœ DB์— ์ €์žฅ๋˜์ง€ ์•Š๊ฒŒ ์“ฐ๊ธฐ ์ง€์—ฐ์„ ์ œ๊ณต ํ•ด์ค€๋‹ค.

์ด๋Š” EntityManager (์˜์†์„ฑ ์ปจํ…์ŠคํŠธ)์•ˆ์— ์บ์‹œ์™€ ํ•จ๊ป˜ ์“ฐ๊ธฐ์ง€์—ฐ SQL ์ €์žฅ์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ฐธ๊ณ ๋กœ JPA๋Š” JDBC Batch๋ฅผ ์ด์šฉํ•˜์—ฌ ์“ฐ๊ธฐ ์ง€์—ฐ์„ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. (hibernate.jdbc.batch_size ์˜ต์…˜ ์„ค์ •๊ฐ€๋Šฅ)

JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด commitํ•˜๋Š” ์‹œ์ ์— ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์„ ๊ฐ์ง€ํ•˜์—ฌ SQL ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์œ„์—๋„ ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ, ๋ฐ”๋กœ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  [์“ฐ๊ธฐ ์ง€์—ฐ SQL ์ €์žฅ์†Œ]์— ์ฟผ๋ฆฌ๋ฅผ ์Œ“์•„๋’€๋‹ค๊ฐ€ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹ํ•˜๋Š” ์‹œ์  (commit)์— ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„๋งŒ ๊ฐ์ง€ํ•˜์—ฌ, ์ตœ์ ํ™”๋œ SQL๋ฌธ์„ ์ƒ์„ฑํ•˜๊ฒŒ ๋œ๋‹ค.

persist()๋ฅผ ํ•œ๋‹ค๊ณ  ํ•ด์„œ, DB์— ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ€์ง€ ์•Š๋Š”๋‹ค. (*๋ฌผ๋ก  ์„ค์ •์œผ๋กœ ์“ฐ๊ธฐ์ง€์—ฐ ์ทจ์†Œ ๊ฐ€๋Šฅ)
์ปค๋ฐ‹ํ•˜๋Š” ์‹œ์ ์— ์ตœ์ ํ™”๋œ SQL์œผ๋กœ DB๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋Ÿฐ ๋ถ€๋ถ„ ๋•Œ๋ฌธ์—, ์ž˜๋งŒ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด JDBC๋ฅผ ๋ฐ”๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค JPA๋ฅผ ๊ฑฐ์น˜๋Š”๊ฒŒ ์„ฑ๋Šฅ์ด ๋” ์ข‹์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด ๋‚˜์˜จ ๊ฒƒ์ด๋‹ค.

 

@ ๋ณ€๊ฒฝ ๊ฐ์ง€ (Dirty Checking)

์ด๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ๊ณผ ๋น„์Šทํ•œ ๋งฅ๋ฝ์ด๋‹ค. JPA๋Š” Entity์˜ ์Šค๋ƒ…์ƒท์„ ์ฐ์–ด๋’€๋‹ค๊ฐ€, ์ปค๋ฐ‹๋˜๋Š” ์‹œ์ ์— ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์„ ์ฐพ์•„ ์ตœ์ ํ™”๋œ SQL์„ ์ƒ์„ฑํ•ด๋‚ธ๋‹ค.

try {
    // ์—…๋ฐ์ดํŠธ๋Š” 2์ค„์ด๋ฉด ๋.
    Member member = entityManager.find(Member.class, 1L);
    member.setName("new Name");
    
    // ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋ณ€๊ฒฝ๋˜๋ฉด ์•Œ์•„์„œ ์ฟผ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
    // ์ด๋Š” ์‹ค์ œ ์ปฌ๋ ‰์…˜๋„ ๊ทธ๋ ‡๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ปฌ๋ ‰์…˜์„ ๋ณ€๊ฒฝํ•˜๊ณ , ๋”ฐ๋กœ ์ €์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ์ ์ด ์žˆ๋˜๊ฐ€?
    tx.commit();
} catch (Exception e) { ... }

* ์ฐธ๊ณ ๋กœ flush๋ฅผ ์‚ฌ์šฉํ•ด๋„ 1์ฐจ์บ์‹œ๋Š” ๋ณ€ํ•จ์—†๋‹ค. ๊ทธ๋Œ€๋กœ ์ œ๊ณต๋จ. (์“ฐ๊ธฐ ์ง€์—ฐ SQL ์ €์žฅ์†Œ๋งŒ ๋ณ€๊ฒฝ)

์ฐธ๊ณ ๋กœ flush() ๋Š” ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ๋ฐ˜์˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ๋งŒ์•ฝ ํ˜ธ์ถœ๋œ๋‹ค๋ฉด [์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์žˆ๋Š” ์ฟผ๋ฆฌ]๋ฅผ DB์— ์ „์†กํ•œ๋‹ค.

์‰ฝ๊ฒŒ๋งํ•ด ํ”Œ๋Ÿฌ์‹œ๋ฅผ ํ•˜๋Š” ์‹œ์ ์— DB ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋ฌผ๋ก  ์ปค๋ฐ‹ํ•˜๊ธฐ ์ „๊นŒ์ง€ ์‹ค์ œ ํ…Œ์ด๋ธ”์— ๋ฐ˜์˜์€ ๋˜์ง€ ์•Š๊ฒ ์ง€๋งŒ.

 

ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๊ฑฐ๋‚˜ JPQL ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋ฉด EntityManager.flush()๊ฐ€ ์ž๋™์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.

๋ฌผ๋ก  EntityManager.flush()๋กœ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค.

JPQL์˜ ๊ฒฝ์šฐ์—๋Š”, ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž„์˜๋กœ ์บ์‹ฑํ•ด์„œ ์“ฐ๊ธฐ์ง€์—ฐ์„ ๋งŒ๋“ค์–ด๋ฒ„๋ฆฌ๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์‰ฝ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ JPQL์„ ์‹คํ–‰ํ•˜๋Š” ์‹œ์ ์— ํ”Œ๋Ÿฌ์‹œ, ์ฆ‰ DB์กฐํšŒ๊ฐ€ ์ผ์–ด๋‚˜๋„๋ก ์„ค์ •๋˜์–ด์žˆ๋‹ค.

 

์ฐธ๊ณ ๋กœ ์ž๋™ ํ”Œ๋Ÿฌ์‹œ๋Š” ์˜ต์…˜์œผ๋กœ ์„ค์ •์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก  ์‚ฌ์šฉํ•  ์ผ์€ ์—†๋‹ค.

์ฟผ๋ฆฌ = JPQL.

ํ—ท๊ฐˆ๋ฆด๊นŒ๋ด ์–ธ๊ธ‰ํ•˜์ง€๋งŒ, ํ”Œ๋Ÿฌ์‹œ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ๋น„์šฐ๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค.

๊ทธ๋ƒฅ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” (์“ฐ๊ธฐ ์ง€์—ฐ๋œ) ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB์— ๋™๊ธฐํ™” ํ•˜๋Š” ๊ฒƒ ๋ฟ์ด๋‹ค.

๋™๊ธฐํ™”๋ฅผ ๋Šฆ๊ฒŒ ํ•ด๋„ ๋˜๋Š” ์ด์œ ๋Š” ํŠธ๋žœ์žญ์…˜ Commit ์ง์ „์—๋งŒ ๋™๊ธฐํ™”๋ฅผ ํ•ด์ฃผ๋ฉด ๋ฌธ์ œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

@ ์ค€์˜์† ์ƒํƒœ

EntityManager์—๋Š” ์กด์žฌํ•˜์ง€๋งŒ, ์˜์†ํ™” ํ•˜์ง€ ์•Š๋Š” ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ตœ๊ทผ์—๋Š” `์ค€์˜์†` ๋Œ€์‹  `์˜์†์ƒํƒœ ๋ถ„๋ฆฌ` ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฉ”์„œ๋“œ ๋ช…๋„ detached() ์ฆ‰ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ณ€๊ฒฝ๊ฐ์ง€, ์“ฐ๊ธฐ ์ง€์—ฐ๋“ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค.

clear()๋Š” ํ…Œ์ŠคํŠธ ๋•Œ JPA์˜ ๋™์ž‘์„ ๋ณด๊ณ ์‹ถ์„ ๋•Œ ์ข…์ข… ์‚ฌ์šฉํ•œ๋‹ค.

๊ทผ๋ฐ JPA์—์„œ ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๊ฑฐ๋ฉด ๊ทธ๋ƒฅ ๋น„์˜์† ์ƒํƒœ, ์ฆ‰ JPA๋ฅผ ์•ˆ๊ฑฐ์น˜๋ฉด ๋  ๊ฑฐ ๊ฐ™์€๋ฐ ์™œ ๊ตณ์ด ์ค€์˜์† ์ƒํƒœ๋ผ๋Š”๊ฑธ ๋‘๊ณ  EntityManager ์•ˆ์—์„œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ๊นŒ?

 

๊ทธ ์ด์œ ๋Š” 'ํ•œ๋ฒˆ ์˜์†์ƒํƒœ๊ฐ€ ๋˜์—ˆ๋‹ค๊ฐ€ ์ทจ์†Œ๋œ ๊ฒฝ์šฐ์—๋„ ๊ฐ์ฒด์˜ ์‹๋ณ„์ž๊ฐ€ ๋‚จ์•„์žˆ๊ธฐ ๋•Œ๋ฌธ' ์ด๋‹ค.

์ด๋Š” ํ‰์†Œ์—๋Š” ๊ฑฐ์˜ ์“ธ ์ผ์ด์—†๊ณ  ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๋•Œ ์ข…์ข… ์“ฐ์ด๋Š”๋ฐ, ์ด๋Š” JPA์— ์–ด๋Š์ •๋„ ์ต์ˆ™ํ•ด ์ง„ ๋‹ค์Œ์— ์ฒœ์ฒœํžˆ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ