TransactionRequiredException ν•΄κ²° - μ΄ˆκΈ°ν™” μ‹œμ μ— Transaction νšλ“

1. κ°œμš”

JPA λ₯Ό μ΄μš©ν•œ ν…ŒμŠ€νŠΈ ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ˜ 쀑 초기 데이터λ₯Ό λŒ€λŸ‰μœΌλ‘œ INSERT ν•΄μ£ΌλŠ” λΉˆμ„ μƒμ„±ν•˜λ € ν•˜μ˜€λ‹€.

@PostConstruct λ₯Ό 톡해 Spring Boot μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ κΈ°λ™λ˜λŠ” μ‹œμ μ— μž‘μ„±ν•΄λ‘” λ‘œμ§μ— μ˜ν•΄ ν…ŒμŠ€νŠΈ 데이터듀이 persist λ˜λŠ” λ°©μ‹μ΄μ—ˆλ‹€.

ν•˜μ§€λ§Œ JPA λ₯Ό 톡해 데이터λ₯Ό Insert ν•˜κΈ° μœ„ν•΄μ„œλŠ” νŠΈλžœμž­μ…˜μ΄ ν•„μš”ν•˜κ³ , λ­”κ°€ μ°μ°ν•œ λŠλ‚Œμ€ λ“€μ—ˆμ§€λ§Œ λŒ€μΆ© @Transactional μ• λ…Έν…Œμ΄μ…˜λ§Œ 뢙이고 μž‘λ™μ„ μ‹œμΌœλ³΄μ•˜λ‹€.

μ½”λ“œλ₯Ό 보면 λ‹€μŒκ³Ό κ°™λ‹€.

@Component
@Transactional
public class TestDataInit {

    @PersistenceContext
    private EntityManager em;

    @PostConstruct
    public void init() {
        for (int i = 0; i < 50; i++) {
            Member member = new Member("member" + i);
            Reservation reservation = new Reservation(member);
            em.persist(reservation);
        }
    }
}

2. 문제 λ°œμƒ

ν•˜μ§€λ§Œ μ—­μ‹œλ‚˜ λ‹€μŒκ³Ό 같은 μ—λŸ¬λ©”μ‹œμ§€κ°€ λ‚˜νƒ€λ‚˜λ©΄μ„œ 기동에 μ‹€νŒ¨ν•˜μ˜€λ‹€.

Error creating bean with name 'testDataInit': Invocation of init method failed; 
nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call

 

λ¬Έμ œλŠ” AOP μ‹€ν–‰κ³Ό μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆ μ΄ˆκΈ°ν™”μ˜ μˆœμ„œ μ°¨μ΄λ•Œλ¬Έμ— λ°œμƒν–ˆλŠ”λ°, μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μ „λΆ€ μ΄ˆκΈ°ν™” λ˜μ–΄μ•Ό AOPκ°€ 적용되기 λ•Œλ¬Έμ— @PostConstruct μ• λ…Έν…Œμ΄μ…˜ (μ»¨ν…Œμ΄λ„ˆ μ΄ˆκΈ°ν™” μ‹œμ ) μ—λŠ” 선언적 νŠΈλžœμž­μ…˜ 관리λ₯Ό μ‚¬μš©ν•  수 μ—†μ—ˆλ˜ 것이닀.

 

 

3. ν•΄κ²°

κ°€μž₯ κ°„λ‹¨ν•œ 방법은 선언적 νŠΈλžœμž­μ…˜ 관리 (AOP μ‚¬μš©) μ—μ„œ ν”„λ‘œκ·Έλž˜λ° 방식 νŠΈλžœμž­μ…˜ κ΄€λ¦¬λ‘œ μ „ν™˜ν•˜λŠ” 것이닀.

PlatformTransactionManager μΈν„°νŽ˜μ΄μŠ€λŠ” μŠ€ν”„λ§ λΆ€νŠΈμ—μ„œ μžλ™μœΌλ‘œ μ£Όμž…ν•΄μ£Όλ―€λ‘œ TrnasactionTemplate 을 μƒμ„±ν•˜μ—¬ νŠΈλžœμž­μ…˜μ„ λ‹€μŒκ³Ό 같이 μˆ˜λ™μœΌλ‘œ μ‹œμž‘ν•΄μ£Όλ©΄ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆ μ‹œμž‘ μ‹œμ μ— νŠΈλžœμž­μ…˜μ„ νšλ“ν•˜μ—¬ jpa λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

@PostConstruct
public void init() {

    TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
    transactionTemplate.execute(status -> {
        for (int i = 0; i < 50; i++) {
            Member member = new Member("member" + i);
            Reservation reservation = new Reservation(member);
            em.persist(reservation);
        }
        return null;
    });
}

 

 

μ°Έκ³ 

- 선언적 νŠΈλžœμž­μ…˜ : `@Transactional` μ• λ…Έν…Œμ΄μ…˜ 등을 μ΄μš©ν•˜μ—¬ AOP 에 μ˜ν•΄ μ™ΈλΆ€ μ˜μ‘΄μ„±μ„ μ΄μš©ν•œ νŠΈλžœμž­μ…˜

- ν”„λ‘œκ·Έλž˜λ° νŠΈλžœμž­μ…˜ : `TransactionTemplate` ν΄λž˜μŠ€λ“±μ„ μ΄μš©ν•˜μ—¬ λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•˜μ—¬ λ²”μœ„λ₯Ό κ΄€λ¦¬ν•˜λŠ” νŠΈλžœμž­μ…˜