[JPA] Transactional

Updated:

Categories:

Tags: , , ,

๐Ÿ“Œ ๊ฐœ์ธ์ ์ธ ๊ณต๊ฐ„์œผ๋กœ ๊ณต๋ถ€๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ๋ณต์Šตํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
์ •ํ™•ํ•˜์ง€ ์•Š์€ ์ •๋ณด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ๋ฐ”๋ž๋‹ˆ๋‹ค :๐Ÿ˜ธ
[ํ‹€๋ฆฐ ๋‚ด์šฉ์€ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ๋ณต๋ฐ›์œผ์‹ค๊ฑฐ์—์š”]

Transaction Intro

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ํ•ต์‹ฌ์ ์ธ ์—ญํ• 
  • ์ด๋•Œ๋™์•ˆ ๋งŒ๋“  ์ปคํ”ผ์ฃผ๋ฌธ ์‹œ์Šคํ…œ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” Transaction ์‚ฌ๋ก€
    1. ์ฃผ๋ฌธ ์ค‘ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๋กœ ๊ฒฐ์ œ ์‹คํŒจํ–ˆ๋Š”๋ฐ DB์— ์ฃผ๋ฌธ์ด ์ •์ƒ๋“ฑ๋ก ๋˜์–ด ์ปคํ”ผ ์ˆ˜๋งŒํผ ์Šคํƒฌํ”„๊ฐ€ ์ฐํžŒ ๊ฒฝ์šฐ
    2. ๊ฒฐ์ œ๋ฅผ ํ–ˆ๋Š”๋ฐ DB์— ์ •์ƒ ๋“ฑ๋ก์ด ๋˜์ง€ ์•Š์•„ ํšŒ์›์ด ์ปคํ”ผ๋ฅผ ๋ฐ›์ง€ ๋ชปํ–ˆ์„ ๋•Œ
    3. ์ฃผ๋ฌธ์€ ์ •์ƒ ๋“ฑ๋ก ๋˜์—ˆ๋Š”๋ฐ ์Šคํƒฌํ”„ ํšŸ์ˆ˜๋งŒ DB์— ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ์ค‘์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ ๋ˆ„์ ์ด ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ

ACID ์›์น™

5์›”์— DB์—์„œ ํ–ˆ์ง€๋งŒ ์ค‘์š”ํ•˜๋‹ˆ๊นŒ ํ•œ๋ฒˆ ๋” ์ •๋ฆฌํ•ด๋ด„!

  1. ์›์ž์„ฑ(Atomicity)
    • ํŠธ๋žœ์žญ์…˜์—์„œ์˜ ์›์ž์„ฑ์ด๋ž€ ์ž‘์—…์„ ๋” ์ด์ƒ ์ชผ๊ฐค ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธ
    • ๋”ฐ๋ผ์„œ ๋…ผ๋ฆฌ์ ์œผ๋กœ ํ•˜๋‚˜์˜ ์ž‘์—…์œผ๋กœ ์ธ์‹ํ•ด์„œ ๋‘˜ ๋‹ค ์„ฑ๊ณตํ•˜๋“ ๊ฐ€ ๋‘˜ ๋‹ค ์‹คํŒจํ•˜๋“ ๊ฐ€(All or Nothing)์ค‘์—์„œ ํ•˜๋‚˜๋กœ๋งŒ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ๋˜์–ด์•ผ ํ•จ.
  2. ์ผ๊ด€์„ฑ(Consistency)
    • ์ผ๊ด€์„ฑ์€ ํŠธ๋žœ์žญ์…˜์ด ์—๋Ÿฌ ์—†์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ข…๋ฃŒ๋  ๊ฒฝ์šฐ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์˜๋„ํ•˜๋Š” ๋Œ€๋กœ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ €์žฅ๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์„ ์˜๋ฏธ
    • ์ฃผ๋ฌธํ•œ ์ปคํ”ผ์˜ ์ˆ˜๋งŒํผ, ์Šคํƒฌํ”„ ํšŸ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋งž๊ฒŒ ์ €์žฅ๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•จ. ๋งŒ์•ฝ์— 3์ด ์•„๋‹Œ ์ˆซ์ž๋กœ ์ฆ๊ฐ€ํ•œ ๊ฐ’์ด ์กฐํšŒ๋œ๋‹ค๋ฉด ์ผ๊ด€์„ฑ์— ์œ„๋ฐฐ๋˜๋Š” ๊ฒƒ
  3. ๊ฒฉ๋ฆฌ์„ฑ(Isolation)
    • ๊ฒฉ๋ฆฌ์„ฑ์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜์ด ์‹คํ–‰๋  ๊ฒฝ์šฐ ๊ฐ๊ฐ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰์ด ๋˜์–ด์•ผ ํ•จ์„ ์˜๋ฏธ
    • ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๊ฐ€ ์ปดํ“จํ„ฐ์—์„œ ์›Œ๋“œ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๊ณ , ๋™์‹œ์— ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด๋กœ ์Œ์•…์„ ๋“ฃ๊ณ  ์žˆ๋‹ค๋ฉด ์šฐ๋ฆฌ ๋ˆˆ์—๋Š” ๋ณด์ด์ง€ ์•Š์ง€๋งŒ CPU๋Š” ์œ„ ๋‘ ๊ฐ€์ง€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์•„์ฃผ ๋น ๋ฅธ ์†๋„๋กœ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉด์„œ ์‹คํ–‰์„ ์‹œํ‚ค๋Š” ๊ฒƒ
    • ์ด์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ญ์‹œ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ๋ชฉ์ ์œผ๋กœ ํ•œ ๊ฐœ ์ด์ƒ์˜ ํŠธ๋žœ์žญ์…˜์„ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๊ฒฝ์šฐ ๊ฐ ํŠธ๋žœ์žญ์…˜์ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰์ด ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ๊ฒฉ๋ฆฌ์„ฑ(Isolation).
  4. ์ง€์†์„ฑ(Durability)
    • ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜๋ฉด ๊ทธ ๊ฒฐ๊ณผ๋Š” ์ง€์†๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ

    • ์ฆ‰, ์ง€์†์„ฑ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ข…๋ฃŒ๋˜์–ด๋„ ๋ฐ์ดํ„ฐ๋Š” ๋ฌผ๋ฆฌ์ ์ธ ์ €์žฅ์†Œ์— ์ €์žฅ๋˜์–ด ์ง€์†์ ์œผ๋กœ ์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ


ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹(commit)๊ณผ ๋กค๋ฐฑ(rollback)

Commit

  • ์ปค๋ฐ‹(commit)์€ ๋ชจ๋“  ์ž‘์—…์„ ์ตœ์ข…์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜ํ•˜๋Š” ๋ช…๋ น์–ด๋กœ์จย commit ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅ๋จ.
  • ๋งŒ์•ฝ commit ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์œผ๋ฉด ์ž‘์—…์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ตœ์ข…์ ์œผ๋กœ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ
  • commit ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜๋ฉด,ย ํ•˜๋‚˜์˜ ํŠธ๋žœ์ ์…˜ ๊ณผ์ •์€ ์ข…๋ฃŒ

๋กค๋ฐฑ(rollback)

  • ๋กค๋ฐฑ(rollback)์€ ์ž‘์—… ์ค‘ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ˆ˜ํ–‰๋œ ์ž‘์—…๋“ค์„ ์ทจ์†Œํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์ด ์ „์˜ ์ƒํƒœ๋กœ ๋˜๋Œ์•„ ๊ฐ€๊ฒŒ ๋จ.

์ธ๋ฉ”๋ชจ๋ฆฌ DB ํŠน์„ฑ์ƒ (H2๋Š” ์ธ๋ฉ”๋ชจ๋ฆฌ DB๋‹ค) , ์ธ๋ฉ”๋ชจ๋ฆฌ DB๋ž€? โ†”

JPA์˜ tx.commit() ๋‚ด๋ถ€

๐Ÿ’ JPA tx.commit() ํ˜ธ์ถœ ๊ณผ์ • ์ดํ•ด๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ ๊ด€๊ณ„๋„

โ€‹

  • ์ถ”์ƒํ™”๋˜์–ด์žˆ์–ด์„œ ๊ตฌํ˜„์ฒด๋ฅผ ์ญ‰ ์ง€๋‚˜๊ฐ€๋‹ค๋ณด๋ฉด ๋งˆ์ง€๋ง‰์— Command๊ฐ€ ์žˆ์Œ.
  • ์šฐ๋ฆฌ๊ฐ€ JPA API๋ฅผ ์‚ฌ์šฉํ•ด์„œ commit์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์€ ๋„ˆ๋ฌด๋‚˜๋„ ๊ฐ„๋‹จํ•œ ์ž‘์—…์ธ๋ฐ, ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ์•„์ฃผ ๋ณต์žกํ•œ ๊ณผ์ •์„ ๊ฑฐ์ณ์„œ ์ตœ์ข…์ ์œผ๋กœ commit ๋ช…๋ น์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ „๋‹ฌ

ํ•˜๋‚˜์˜ ์ž‘์—… ๋‹จ์œ„๋กœ ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ๋˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์–ด๋–ค ์‹์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•˜๋ฉด ์ข‹์„์ง€์— ๋Œ€ํ•ด์„œ ๊ผญ ๊ณ ๋ฏผํ•ด๋ณด๊ธฐ

์„ ์–ธํ˜• ๋ฐฉ์‹์˜ ํŠธ๋žœ์žญ์…˜

๐Ÿ”‘ ์š”์•ฝ

โœ”๏ธ Class level๊ณผ Method level์— ์„ค์ • ๊ฐ€๋Šฅ, ๋‘˜ ๋‹ค ์„ค์ •ํ–ˆ์„ ๊ฒฝ์šฐ์—๋Š” Method๊ฐ€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค

โœ”๏ธ Checked exception๋Š” @Transactional ์• ๋„ˆํ…Œ์ด์…˜๋งŒ ์ถ”๊ฐ€ํ•ด์„œ๋Š” rollback์ด ๋˜์ง€ ์•Š์Œ โ†’ ์†์„ฑ์— rollbackFor๋กœ ์ง€์ •ํ•ด ์ฃผ์–ด์•ผ ํ•จ

โœ”๏ธ Ex ) @Transactional(rollbackForย = {SQLException.class, DataFormatException.class})

์• ๋„ˆํ…Œ์ด์…˜ ๋ฐฉ์‹ @Transactional

  1. class level์— ์ ์šฉ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
     ...
     **import org.springframework.transaction.annotation.Transactional;**
        
     @Service
     @Transactional   // (1)
     public class MemberService {
         private final MemberRepository memberRepository;
        
         public MemberService(MemberRepository memberRepository) {
             this.memberRepository = memberRepository;
         }
        
         public Member createMember(Member member) {
             verifyExistsEmail(member.getEmail());
        
             return memberRepository.save(member);
         }
     		...
     }
    
    • MemberRepository์˜ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ํŠธ๋žœ์žญ์…˜์ด ์ ์šฉ
  2. JPA ๋กœ๊ทธ๋ ˆ๋ฒจ ์„ค์ •

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
     spring:
       h2:
         console:
           enabled: true
           path: /h2
       datasource:
         url: jdbc:h2:mem:test
       jpa:
         hibernate:
     ...
     ...
        
     logging:         # (1) ๋กœ๊ทธ ๋ ˆ๋ฒจ ์„ค์ •
       level:
         org:
           springframework:
             orm:
               jpa: DEBUG
    
  3. ์ฝ˜์†” log ํ™•์ธ

    • application ์‹คํ–‰ํ•˜์—ฌ Postman์œผ๋กœ ํšŒ์› ๋“ฑ๋ก ํ›„ log ํ™•์ธ
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
     ...
     2024-06-25 22:19:55.876 DEBUG 46820 --- [nio-8080-exec-4] o.s.orm.jpa.JpaTransactionManager        
     : Found thread-bound EntityManager [SessionImpl(1398140194<open>)] for JPA transactio      
       //(1)
     : **Creating new transaction with name** [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
        
     : PROPAGATION_REQUIRED,ISOLATION_DEFAULT
       //(2)
     2024-06-25 22:19:55.887 DEBUG 46820 --- [nio-8080-exec-4] o.s.orm.jpa.JpaTransactionManager        
     : Initiating transaction commit
     2024-06-25 22:19:55.887 DEBUG 46820 --- [nio-8080-exec-4] o.s.orm.jpa.JpaTransactionManager        
     : Committing JPA transaction on EntityManager [SessionImpl(1398140194<open>)]
     2024-06-25 22:19:55.899 DEBUG 46820 --- [nio-8080-exec-4] o.s.orm.jpa.JpaTransactionManager        
     : Not closing pre-bound JPA EntityManager after transaction   //(3)
       //(4)
     2024-06-25 22:19:55.910 DEBUG 46820 --- [nio-8080-exec-4] o.j.s.OpenEntityManagerInViewInterceptor 
     : Closing JPA EntityManager in OpenEntityManagerInViewIntercepto
    
    • (1) : CoffeeService์˜ createCoffee() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด์„œ ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜์ด ์ƒ์„ฑ
    • (2) : ํŠธ๋žœ์žญ์…˜์—์„œ commit์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ์Œ
    • (3) : ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋จ
    • (4) : JPA์˜ EntityManager๋ฅผ ์ข…๋ฃŒ


  4. roolback ๋™์ž‘ ์œ ๋ฌด ํ™•์ธ

    • createMember() ๋ฉ”์„œ๋“œ์—์„œ ํšŒ์› ์ •๋ณด ์ €์žฅํ•˜๊ณ  ๋ฉ”์„œ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ ์ „์— ๊ฐ•์ œ๋กœ ์˜ˆ์™ธ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ.

      ๋กค๋ฐฑ ํ›„ ์˜ˆ์™ธ ๋˜์ง.



Checked Exception

  • Checked ์˜ˆ์™ธ๋กœ ํ• ๋ ค๋ฉด ์‹คํ–‰์กฐ์ฐจ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— throw๋กœ ๋˜์ ธ์•ผ ์‹คํ–‰ํ•  ์ˆ˜ ์ž‡์Œ.

  • ์ด ์˜ˆ์™ธ๋„ ๋กค๋ฐฑํ•ด์ฃผ์„ธ์š” ๋ผ๊ณ  attribute ๋„ฃ์–ด์•ผ ํ•จ โ†’ ์•ˆ ๋„ฃ์œผ๋ฉด ๋กค๋ฐฑ ์•ˆ๋จ!


Class Level ๊ณผ Method Level์— ์ ์šฉ์‹œ

  1. ํด๋ž˜์Šค ๋ ˆ๋ฒจ๊ณผ ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์˜ ํŠธ๋žœ์žญ์„  ์ ์šฉ ์ˆœ์„œ
    • ํด๋ž˜์Šค ๋ ˆ๋ฒจ์—๋งŒ @Transactional์ด ์ ์šฉ๋œ ๊ฒฝ์šฐ
      • ํด๋ž˜์Šค ๋ ˆ๋ฒจ์˜ @Transactional ์• ๋„ˆํ…Œ์ด์…˜์ด ๋ฉ”์„œ๋“œ์— ์ผ๊ด„ ์ ์šฉ๋จ
    • ํด๋ž˜์Šค ๋ ˆ๋ฒจ๊ณผ ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์— ํ•จ๊ป˜ ์ ์šฉ๋œ ๊ฒฝ์šฐ
      • ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์˜ @Transactional ์• ๋„ˆํ…Œ์ด์…˜์ด ์ ์šฉ๋จ
      • ๋งŒ์•ฝ ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์— @Transactional ์• ๋„ˆํ…Œ์ด์…˜์ด ์ ์šฉ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ, ํด๋ž˜์Šค ๋ ˆ๋ฒจ์˜ @Transactional ์• ๋„ˆํ…Œ์ด์…˜์ด ์ ์šฉ
  2. ๋ฉ”์„œ๋“œ๋ ˆ๋ฒจ์—์„œ @Transactional(readOnly = true) ์ ์šฉ

    โ†’ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์„ค์ • ํ•˜๋Š” ๊ฒƒ :

    โ†’ ์ด์œ  : commit์ด ๋˜์ง€ ์•Š์•„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— flush๋„ ํ•˜์ง€ ์•Š๊ณ  ์Šค๋ƒ…์ƒท์„ ์ƒ์„ฑํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ถˆํ•„์š”ํ•œ ์ถ”๊ฐ€๋™์ž‘์„ ์ค„์ผ ์ˆ˜ ์žˆ์Œ.

    โ†’ ์ฆ‰ ์กฐํšŒ ๋ฉ”์„œ๋“œ์—๋Š” readOnly=true ๋กœ ์„ค์ •ํ•˜์—ฌ JPA๊ฐ€ ์ž์ฒด์ ์œผ๋กœ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ณผ์ •์„ ๊ฑฐ์น˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ!

์—ฌ๋Ÿฌ ์ž‘์—…์ด ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์ผ ๊ฒฝ์šฐ

โ€‹

  • OrderService์—์„œ createOrder() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ, ๋‚ด๋ถ€์—์„œ ์ฃผ๋ฌธ ์ •๋ณด ์ €์žฅ์„ ์œ„ํ•œ ํŠธ๋žœ์žญ์…˜์ด ํ•˜๋‚˜ ์‹œ์ž‘๋˜๋ฉฐ, ๋‹ค์Œ์œผ๋กœ memberService.updateStamp() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํ†ตํ•ด์„œ MemberService์—์„œ ์Šคํƒฌํ”„ ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•œ ํŠธ๋žœ์žญ์…˜์ด ํ•˜๋‚˜ ๋” ์‹œ์ž‘๋จ
  • ๋งŒ์•ฝ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค๋ฉด updateStamp() ๋™์ž‘์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์Šคํƒฌํ”„ ์ˆซ์ž๋Š” ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์•˜๋Š”๋ฐ ์ฃผ๋ฌธ ์ •๋ณด๋Š” ์ €์žฅ๋˜๋Š” ์›์น˜ ์•Š๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•จ

โ€‹

  • ํŠธ๋žœ์žญ์…˜์ด ํ•˜๋‚˜๋กœ ๋ฌถ์ด๋ฉด MemberService์˜ updateStamp() ๋ฉ”์„œ๋“œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋„์ค‘์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๋‘ ํด๋ž˜์Šค์—์„œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋“ค์ด ๋ชจ๋‘ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ๋‚ด์— ์žˆ์œผ๋ฏ€๋กœ ๋ชจ๋‘ rollbacK ๋จ

Attribute ์„ค์ •์œผ๋กœ Transaction ์ „ํŒŒ์™€ ๊ฒฉ๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ.

๐Ÿ”Ž ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ (Transaction Propagation)

ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฝ๊ณ„์—์„œ ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์กด์žฌํ•  ๋•Œ ๋˜๋Š” ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ, ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•  ๊ฒƒ์ธ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐฉ์‹์„ ์˜๋ฏธ

  1. @Transactional(propagation = Propagation.REQUIRED)
    • ํ˜„์žฌ ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์กด์žฌํ•˜๋ฉด ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๊ณ , ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒˆ ํŠธ๋žœ์žญ์…˜์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•ด์คŒ
    • ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” propagation ์œ ํ˜•์˜ ๋””ํดํŠธ ๊ฐ’
  2. @Transactional(Propagation.REQUIRES_NEW)
    • ์ด๋ฏธ ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘
    • ๊ธฐ์กด์— ์ง„ํ–‰ ์ค‘์ด๋˜ ํŠธ๋žœ์žญ์…˜์€ ์ƒˆ๋กœ ์‹œ์ž‘๋œ ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ์ค‘์ง€๋จ
  3. @Transactional(Propagation.MANDATORY)
    • ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์—†์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ด
  4. @Transactional(Propagation.NOT_SUPPORTED)
    • ํŠธ๋žœ์žญ์…˜์„ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š์Œ์„ ์˜๋ฏธ
    • ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์žˆ์œผ๋ฉด ๋ฉ”์„œ๋“œ ์‹คํ–‰์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์€ ์ค‘์ง€๋˜๋ฉฐ, ๋ฉ”์„œ๋“œ ์‹คํ–‰์ด ์ข…๋ฃŒ๋˜๋ฉด ํŠธ๋žœ์žญ์…˜์„ ๊ณ„์† ์ง„ํ–‰
  5. @Transactional(Propagation.NEVER)
    • ํŠธ๋žœ์žญ์…˜์„ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š์Œ์„ ์˜๋ฏธ
    • ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์กด์žฌํ•  ๊ฒฝ์šฐ์—๋Š” ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ด

๐Ÿ”Ž ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ(Isolation Level)

ํŠธ๋žœ์žญ์…˜์€ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ , ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฉ๋ฆฌ์„ฑ์ด ๋ณด์žฅ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ Spring์€ ์ด๋Ÿฌํ•œ ๊ฒฉ๋ฆฌ์„ฑ์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์„ @Transactional ์• ๋„ˆํ…Œ์ด์…˜์˜ isolation ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ํ†ตํ•ด ์ œ๊ณตํ•จ

  1. @Transactional (Isolation.DEFAULT)

    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ๊ฐ’
  2. @Transactional(Isolation.READ_UNCOMMITTED) ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•จ

  3. @Transactional(Isolation.READ_COMMITTED) ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์— ์˜ํ•ด ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•จ

  4. @Transactional(Isolation.REPEATABLE_READ) ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ํ•œ ๋ฒˆ ์กฐํšŒํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ์กฐํšŒํ•ด๋„ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์กฐํšŒ๋˜๋„๋ก ํ•จ

  5. @Transactional(Isolation.SERIALIZABLE) ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด์„œ ๋™์‹œ์— ๋‘ ๊ฐœ ์ด์ƒ์˜ ํŠธ๋žœ์žญ์…˜์ด ์ˆ˜ํ–‰๋˜์ง€ ๋ชปํ•˜๋„๋ก ํ•จ

    ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ ๋ฐ์ดํ„ฐ์†Œ์Šค์— ์„ค์ •๋œ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋˜๋ฏ€๋กœ, ์ด๋Ÿฌํ•œ ๊ฒฉ๋ฆฌ ๋ ˆ๋ฒจ์ด ์žˆ๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.


AOP ๋ฐฉ์‹์˜ ํŠธ๋žœ์žญ์…˜ ์ ์šฉ

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ ์šฉํ•˜์ง€ ์•Š๊ณ , ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.*;
import java.util.HashMap;
import java.util.Map;

// (1)
@Configuration
public class TxConfig {
    private final TransactionManager transactionManager;

		// (2)
    public TxConfig(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    @Bean
    public TransactionInterceptor txAdvice() {
        NameMatchTransactionAttributeSource txAttributeSource =
                                    new NameMatchTransactionAttributeSource();

				// (3)
        RuleBasedTransactionAttribute txAttribute =
                                        new RuleBasedTransactionAttribute();
        txAttribute.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

				// (4)
        RuleBasedTransactionAttribute txFindAttribute =
                                        new RuleBasedTransactionAttribute();
        txFindAttribute.setPropagationBehavior(
                                        TransactionDefinition.PROPAGATION_REQUIRED);
        txFindAttribute.setReadOnly(true);

				// (5)
        Map<String, TransactionAttribute> txMethods = new HashMap<>();
        txMethods.put("find*", txFindAttribute);
        txMethods.put("*", txAttribute);

				// (6)
        txAttributeSource.setNameMap(txMethods);

				// (7)
        return new TransactionInterceptor(transactionManager, txAttributeSource);
    }

    @Bean
    public Advisor txAdvisor() {
				// (8)
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* com.codestates.coffee.service." +
                "CoffeeService.*(..))");

        return new DefaultPointcutAdvisor(pointcut, txAdvice());  // (9)
    }
}

AOP ๋ฐฉ์‹์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•˜๋Š” ์ˆœ์„œ

  1. AOP ๋ฐฉ์‹์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ Configuration ํด๋ž˜์Šค ์ •์˜

    (1)๊ณผ ๊ฐ™์ด @Configuration ์• ๋„ˆํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉฐ Configuration ํด๋ž˜์Šค๋ฅผ ์ •์˜

  2. TransactionManager DI

    ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” TransactionManager ๊ฐ์ฒด๊ฐ€ ํ•„์š” โ†’ (2)์™€ ๊ฐ™์ด TransactionManager ๊ฐ์ฒด๋ฅผ DI ๋ฐ›์Šต๋‹ˆ๋‹ค.

  3. ํŠธ๋žœ์žญ์…˜ ์–ด๋“œ๋ฐ”์ด์Šค์šฉ TransactionInterceptor ๋นˆ ๋“ฑ๋ก

    Spring์—์„œ๋Š” TransactionInterceptor๋ฅผ ์ด์šฉํ•ด์„œ ๋Œ€์ƒ ํด๋ž˜์Šค ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„๋ฅผ ์„ค์ •ํ•˜๊ณ  ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    • ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ ์ง€์ •
      • ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ํŒจํ„ด์— ๋”ฐ๋ผ ๊ตฌ๋ถ„ํ•ด์„œ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— (3), (4)์™€ ๊ฐ™์ด ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
      • (3)์€ ์กฐํšŒ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ์™ธํ•œ ๊ณตํ†ต ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ์ด๊ณ , (4)๋Š” ์กฐํšŒ ๋ฉ”์„œ๋“œ์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ
    • ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•  ๋ฉ”์„œ๋“œ์— ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ ๋งคํ•‘
      • ์„ค์ •ํ•œ ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋Š” (5)์™€ ๊ฐ™์ด Map์— ์ถ”๊ฐ€ํ•˜๋Š”๋ฐ, Map์˜ key๋ฅผ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ํŒจํ„ด์œผ๋กœ ์ง€์ •ํ•ด์„œ ๊ฐ๊ฐ์˜ ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ถ”๊ฐ€
      • ํŠธ๋žœ์žญ์…˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ถ”๊ฐ€ํ•œ Map ๊ฐ์ฒด๋ฅผ (6)๊ณผ ๊ฐ™์ด txAttributeSource.setNameMap(txMethods)์œผ๋กœ ๋„˜๊ฒจ์คŒ
    • TransactionInterceptor ๊ฐ์ฒด ์ƒ์„ฑ
      • (7)๊ณผ ๊ฐ™์ด TransactionInterceptor์˜ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ transactionManager์™€ txAttributeSource๋ฅผ ์ „๋‹ฌ
  4. Advisor ๋นˆ ๋“ฑ๋ก

    • ํฌ์ธํŠธ ์ปท ์ง€์ •
      • ์ด์ œ ํŠธ๋žœ์žญ์…˜ ์–ด๋“œ๋ฐ”์ด์Šค์ธ TransactionInterceptor๋ฅผ ํƒ€๊นƒ ํด๋ž˜์Šค์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํฌ์ธํŠธ ์ปท์„ ์ง€์ •
      • (8)๊ณผ ๊ฐ™์ด AspectJExpressionPointcut ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ํ›„, ํฌ์ธํŠธ ์ปท ํ‘œํ˜„์‹์œผ๋กœ CoffeeService ํด๋ž˜์Šค๋ฅผ ํƒ€๊นƒ ํด๋ž˜์Šค๋กœ ์ง€์ •
    • Advisor ๊ฐ์ฒด ์ƒ์„ฑ

      ๋งˆ์ง€๋ง‰์œผ๋กœ (9)์™€ ๊ฐ™์ด DefaultPointcutAdvisor์˜ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํฌ์ธํŠธ์ปท๊ณผ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์ „๋‹ฌํ•ด ์ค€๋‹ค.


  • AOP๊ฐ€ ์ ์šฉ๋˜์–ด์žˆ๋‹ค๋Š” ๊ฒƒ์€ ํ”„๋ก์‹œํŒจํ„ด์ด ์ ์šฉ๋˜์–ด์žˆ๋‹ค๋Š”๊ฒƒ.

  • ํ”„๋ก์‹œ๊ฐ์ฒด๋Š” ์›๋ณธ๊ฐ์ฒด์™€ ๋‹ฌ๋ฆฌ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์ด ํฌํ•จ๋˜์–ด์ž‡์Œ.

  • SPRING AOP๋Š” ๊ฐ€์ƒ์˜ ํ”„๋ก์‹œ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ค‘๊ฐ„์— ๋‚š์•„ ์ฑˆ ํ›„ ํ”„๋ก์‹œ๊ฐ์ฒด๊ฐ€ ์‹คํ–‰๋จ โ†’ ์–˜๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋†“์ง€ ์•Š๊ณ  ์š”์ฒญ์ด ์™”์„ ๋•Œ ๋™์ ์œผ๋กœ ๋งŒ๋“ฌ. ๊ฐ€์ƒ์˜ ์ธ์œ„์˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  ๋‹ค์“ฐ๋ฉด ์ง€์›Œ๋ฒ„๋ฆผ

  • ๋‚ด๋ถ€์ ์œผ๋กœ GCLIB๋ผ๋Š” ๊ธฐ์ˆ ์„ ์‚ฌ์šฉ,,

  • AOP๋ฅผ ์จ์„œ TRANSACTION์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„์•ผ ํ•จ. (Spring AOP โ‡’ SPRING Transaction)

  • ํ”„๋ก์‹œ๋Š” ์•ž๋‹จ์— ๋จผ์ € ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ€์ƒ์˜ ์„œ๋ฒ„, ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ฒƒ๋„ ํ”„๋ก์‹œ - AOP๊ฐ€ ์ ์šฉ๋œ ๊ฒƒ.


(์ฐธ๊ณ ) Springboot์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Configuration
@EnableTransactionManagement
public class JpaConfig{

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
        final LocalContainerEntityManagerFactoryBean em =
				new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        ...
        ...

        return em;
    }

		// (1)
    @Bean
    public DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();

				...
				...

        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();    // (2)
        transactionManager.setEntityManagerFactory(
                entityManagerFactoryBean().getObject() );
        return transactionManager;
    }
}

  • (1)๊ณผ ๊ฐ™์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” Datasource๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•„์š”
  • Spring์—์„œ ํŠธ๋žœ์žญ์…˜์€ ๊ธฐ๋ณธ์ ์œผ๋กœ PlatformTransactionManager์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋ฉฐ, PlatformTransactionManager ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๊ธฐ์ˆ ์— ๋งž๊ฒŒ ์œ ์—ฐํ•˜๊ฒŒ ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ถ”์ƒํ™”๋˜์–ด ์žˆ์Œ
  • ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๊ธฐ์ˆ ์ด JPA์ด๊ธฐ ๋•Œ๋ฌธ์— (2)์™€ ๊ฐ™์ด PlatformTransactionManager์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค์ธ JpaTransactionManager๋ฅผ ์‚ฌ์šฉ

Spring ์นดํ…Œ๊ณ ๋ฆฌ ๋‚ด ๋‹ค๋ฅธ ๊ธ€ ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

Leave a comment