# ํŠธ๋žœ์žญ์…˜ ์ธํ„ฐํŽ˜์ด์Šค, ํŠธ๋žœ์žญ์…˜ ํ…œํ”Œ๋ฆฟ์„ ์ด์šฉํ•œ Service ๊ณ„์ธต์˜ Transaction ๋ฌธ์ œ ํ•ด๊ฒฐ
Study Repository

ํŠธ๋žœ์žญ์…˜ ์ธํ„ฐํŽ˜์ด์Šค, ํŠธ๋žœ์žญ์…˜ ํ…œํ”Œ๋ฆฟ์„ ์ด์šฉํ•œ Service ๊ณ„์ธต์˜ Transaction ๋ฌธ์ œ ํ•ด๊ฒฐ

by rlaehddnd0422

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์กฐ 

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์กฐ ์ค‘ ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๋ฉด์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ญํ• ์— ๋”ฐ๋ผ 3๊ฐ€์ง€ ๊ณ„์ธต์œผ๋กœ ๋‚˜๋ˆ„๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ ๊ณ„์ธต

  • ์›น ์š”์ฒญ(request), ์‘๋‹ต(response)๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์‚ฌ์šฉ์ž ์š”์ฒญ์„ ๊ฒ€์ฆํ•˜๋Š” ์—ญํ• 
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ ‘๊ทผํ•˜๋Š” UI ๊ด€๋ จ๋œ ๊ธฐ์ˆ ์ธ ์›น, ์„œ๋ธ”๋ฆฟ, HTTP์™€ ๊ด€๋ จ๋œ ๋ถ€๋ถ„์„ ๋‹ด๋‹น  
  • ์ฃผ๋กœ Servlety๊ณผ HTTP ๊ฐ™์€ ์›น ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๊ณ  MVC(Model + View + Controller)๊ตฌ์กฐ๋ฅผ ์ด๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋น„์Šค ๊ณ„์ธต

  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋Š” ๊ณ„์ธต์ž…๋‹ˆ๋‹ค.
  • ํŠน์ • ๊ธฐ์ˆ ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์ˆœ์ˆ˜ ์ž๋ฐ”์ฝ”๋“œ๋กœ ์ž‘์„ฑ

๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต 

  • ์‹ค์ œ DB์— ์ ‘๊ทผํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋œ ๊ณ„์ธต
  • ์ฃผ๋กœ JDBC, JPA ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

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

์„œ๋น„์Šค ๊ณ„์ธต์„ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ์š”? 

 

์ด ์ „ ํฌ์ŠคํŒ…์—์„œ ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด์•˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž ๊น ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด

@Slf4j
@RequiredArgsConstructor
public class MemberServiceV2 {
    private final MemberRepositoryV2 memberRepository;
    private final DataSource dataSource;

    public void accountTransfer(String fromId, String toId, int money) throws SQLException {
        Connection con = dataSource.getConnection();
        try
        {
            con.setAutoCommit(false); // ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
            buisnesslogic(con, fromId, toId, money);
            con.commit();
        } catch (Exception e) {
            log.error("error detected!");
            con.rollback();
            throw new IllegalStateException(e);
        } finally {
            release(con);
        }
    }
  • ์„œ๋น„์Šค ๊ณ„์ธต์˜ ๊ณ„์ขŒ์ด์ฒด ๋กœ์ง์„ ๋ณด๋ฉด ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋กค๋ฐฑํ•˜๊ณ , ์ตœ์ข…์ ์œผ๋กœ connection์„ ๋ฐ˜๋‚ฉํ•˜๋Š” ์ž‘์—…๊นŒ์ง€ ๋ชจ๋‘ ํ•œ ๋กœ์ง(๋ฉ”์†Œ๋“œ)์—์„œ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต์œผ๋กœ๋ถ€ํ„ฐ ์˜ฌ๋ผ์˜ค๋Š” SQLException ๋˜ํ•œ JDBC ๊ธฐ์ˆ ์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋ ‡๊ฒŒ ์„œ๋น„์Šค ๊ณ„์ธต์—์„  ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋งŒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š”๋ฐ ๊ทธ๋ ‡์ง€ ๋ชปํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์„ ํ•˜๊ธฐ ์œ„ํ•ด JDBC ๊ธฐ์ˆ (DataSource๋ฅผ ํ†ตํ•œ ์ปค๋„ฅ์…˜ ํš๋“)์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”.
  • ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๋งŒ์•ฝ JDBC ๊ธฐ์ˆ ์—์„œ JPA ๊ฐ™์ด ๋‹ค๋ฅธ ๊ธฐ์ˆ ๋กœ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋˜๋ฉด ์ „์ฒด์ ์ธ ์„œ๋น„์Šค ๊ณ„์ธต์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. 

 

์ •๋ฆฌํ•˜๋ฉด ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ์ด 3๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. 

1. ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ : JDBC ๊ตฌํ˜„ ๊ธฐ์ˆ ์ด ์„œ๋น„์Šค ๊ณ„์ธต์— ๊ตฌํ˜„, ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ปค๋„ฅ์…˜์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ฆ์œผ๋กœ์จ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋”ฉ

 

2. JDBC ๋ฐ˜๋ณต ๋ฌธ์ œ : try-catch-finally ์™€ ์ปค๋„ฅ์…˜์„ ๋ฐ›๊ณ  pstmt ์‚ฌ์šฉํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ๋งคํ•‘, ์‹คํ–‰์˜ ๋ฐ˜๋ณต .. 

 

2. ์˜ˆ์™ธ ๋ˆ„์ˆ˜ ๋ฌธ์ œ : Repository ๊ณ„์ธต์œผ๋กœ๋ถ€ํ„ฐ ์ „ํŒŒ๋œ ์˜ˆ์™ธ๊ฐ€ JDBC ๊ธฐ์ˆ ์„ ์˜์กดํ•˜๋Š” ๋ฌธ์ œ

 

์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์€ ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•ด์„œ ์„œ๋น„์Šค ๊ณ„์ธต์„ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋ฉด์„œ ์œ„์— ๊ธฐ์ˆ ํ•œ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 


Sol 1. ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” - (Service ๊ณ„์ธต TransactionManager) + (Repository ๊ณ„์ธต Transaction Synchronize Manager)

ํ˜„์žฌ ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์„ ํ•˜๊ธฐ ์œ„ํ•ด JDBC ๊ธฐ์ˆ ์— ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์•„์˜ˆ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ธฐ์ˆ ์ธ JPA๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ์„œ๋น„์Šค ๊ณ„์ธต์˜ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ จ ์ฝ”๋“œ๋„ ๋ชจ๋‘ ํ•จ๊ป˜ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

(JDBC์€ con.setAutoCommit(false)์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜์ง€๋งŒ, JPA๋Š” transaction.begin()์„ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘)

 

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ํŠธ๋žœ์žญ์…˜ ๊ธฐ๋Šฅ์„ ์ถ”์ƒํ™” ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์Šคํ”„๋ง์€ ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” ๊ธฐ์ˆ ์„ ์ด๋ฏธ ์ œ๊ณตํ•˜๊ณ  ์žˆ๊ธฐ ๋–„๋ฌธ์— ์ด ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ์ถ”์ƒํ™”์— ์˜์กดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ์ธํ„ฐํŽ˜์ด์Šค PlatformTransactionManager

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” ๊ธฐ์ˆ ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋Š” PlatformTransactionManager์ž…๋‹ˆ๋‹ค.

public interface PlatformTransactionManager extends TransactionManager {


   TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
         throws TransactionException;

   void commit(TransactionStatus status) throws TransactionException;

   void rollback(TransactionStatus status) throws TransactionException;

}
  • getTransaction() : ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘
  • commit() : ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹
  • rollback() : ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑ 

์ด์ œ ์ถ”์ƒํ™”๋ฅผ ์‚ฌ์šฉํ•ด ์ด์ œ DataSource๋ฅผ ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ PlatformTransactionManager ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กด(์™ธ๋ถ€์—์„œ ๊ตฌํ˜„์ฒด ์ฃผ์ž…)ํ•ด์„œ ํŠธ๋žœ์žญ์…˜์„ ์ƒ์„ฑ, ์ปค๋ฐ‹, ๋กค๋ฐฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋น„์Šค ๊ณ„์ธต์˜ PlatformTranscationManager๋ฅผ ์ค„์—ฌ์„œ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ผ๊ณ  ์นญํ•ฉ๋‹ˆ๋‹ค.

 

 

์ถ”๊ฐ€๋กœ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต์—์„œ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ์ปค๋„ฅ์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์— ๋ณด๊ด€๋˜์–ด ์žˆ๋Š” ์ปค๋„ฅ์…˜์„ ๋ฐ›์•„์˜ฌ ๋•Œ DataSourceUtils์˜ getConnection()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. 

// ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด DataSourceUtils๋ฅผ ํ†ตํ•ด ์ปค๋„ฅ์…˜์–ป์–ด์•ผํ•จ.
Connection con = DataSourceUtils.getConnection(dataSource);

 

ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋Š” ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์ด๋ผ๋Š” ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด ์ปค๋„ฅ์…˜์„ ๋™๊ธฐํ™” ํ•ด์ค๋‹ˆ๋‹ค. ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์€ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ์ƒํ™ฉ์— ์•ˆ์ „ํ•˜๊ฒŒ ์ปค๋„ฅ์…˜์„ ๋™๊ธฐํ™” ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ์ƒ์„ฑํ•œ ์ปค๋„ฅ์…˜์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต์— ๋„˜๊ฒจ์ค„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!

 

์œ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์„œ๋น„์Šค ๊ณ„์ธต๊ณผ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

Service ๊ณ„์ธต 

@Slf4j
@RequiredArgsConstructor
public class MemberServiceV3_1 {
    private final PlatformTransactionManager transactionManager;
    private final MemberRepositoryV3 memberRepository;

    public void accountTransfer(String fromId, String toId, int money) throws SQLException 
    {
        // ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
        // ์ปค๋„ฅ์…˜ ์ƒ์„ฑ
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

        try
        {
            buisnesslogic(fromId, toId, money);
            transactionManager.commit(status);
        } catch (Exception e) {
            log.error("error detected!");
            transactionManager.rollback(status);
            throw new IllegalStateException(e);
        } // release๋Š” transactionManager๊ฐ€ ์•Œ์•„์„œ ํ•ด์คŒ.
	}

ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๊ฐ€ dataSource๋ฅผ ํ†ตํ•ด ์ปค๋„ฅ์…˜์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋•๋ถ„์— ์ด์ œ ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ๋Š” dataSource๋ฅผ ์˜์กดํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์˜ ๊ตฌํ˜„์ฒด๋Š” JDBC ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ DataSourceTransactionManager ๊ตฌํ˜„์ฒด๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. 

(dataSource๋˜ํ•œ JDBC ๊ธฐ์ˆ ์˜ DriverManagerDataSource ๊ตฌํ˜„์ฒด๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค)

  • transactionManager๋Š” getTransaction()์„ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ์ƒ์„ฑํ•˜๊ณ , status๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. status์—๋Š” ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜์˜ ์ƒํƒœ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด, ์ปค๋ฐ‹, ๋กค๋ฐฑ์—์„œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. 
    • getTransaction ๋‚ด๋ถ€ ํŒŒ๋ผ๋ฏธํ„ฐ์— ํŠธ๋žœ์žญ์…˜ ๊ด€๋ จ ์˜ต์…˜์„ ์ง€์ •๊ฐ€๋Šฅ. ์—ฌ๊ธฐ์„œ๋Š” Default์ธ DefaultTransactionDefinition ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉ
  • transactionManager.commit(status) : ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹
  • transactionManager.rollback(status) : ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ

Repository ๊ณ„์ธต

@Slf4j
@RequiredArgsConstructor
public class MemberRepositoryV3 {
    private final DataSource dataSource;
    
    private Connection getConnection() throws SQLException {

        // ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด DataSourceUtils๋ฅผ ํ†ตํ•ด ์ปค๋„ฅ์…˜์–ป์–ด์•ผํ•จ.
        Connection con = DataSourceUtils.getConnection(dataSource);
        log.info("get connection = {}, class = {}",con,con.getClass());
        return con;
    }

    private void close(Connection con, Statement stmt, ResultSet rs)
    {
        JdbcUtils.closeResultSet(rs);
        JdbcUtils.closeStatement(stmt);

        // ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด DataSourceUtils ์‚ฌ์šฉํ•ด์•ผ ํ•จ.
        // ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋™๊ธฐํ™”๋œ ์ปค๋„ฅ์…˜์€ ๋‹ซ์ง€ ์•Š๊ณ  ์œ ์ง€.
        // ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ปค๋„ฅ์…˜์ด ์—†๋Š” ๊ฒฝ์šฐ์—” ํ•ด๋‹น ์ปค๋„ฅ์…˜ ๋‹ซ์Œ.
        DataSourceUtils.releaseConnection(con,dataSource);
    }
  • ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ์ปค๋„ฅ์…˜์€ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์— ๋ณด๊ด€๋ฉ๋‹ˆ๋‹ค!
  • ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์— ๋ณด๊ด€๋œ ์ปค๋„ฅ์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ DataSourceUtils์˜ getConnection(dataSource)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. (dataSource๋Š” ์™ธ๋ถ€์—์„œ DriverManagerDataSource ๊ตฌํ˜„์ฒด๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉ)  
  • ์ปค๋ฐ‹์ด๋‚˜ ๋กค๋ฐฑ์ดํ›„ ์ตœ์ข…์ ์œผ๋กœ ์ปค๋„ฅ์…˜์€ ๋ฐ˜๋“œ์‹œ DataSourceUtils์˜ releaseConnection ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™๊ธฐํ™”๋˜์–ด ์žˆ๋Š” ์ปค๋„ฅ์…˜์˜ ๊ฒฝ์šฐ์—๋Š” ์ปค๋„ฅ์…˜์„ ๋‹ซ์ง€์•Š๊ณ  ์œ ์ง€ํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜์ด ๋๋‚œ ๊ฒฝ์šฐ(๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ปค๋„ฅ์…˜์ด ์—†๋Š” ๊ฒฝ์šฐ)์—๋Š” ์ปค๋„ฅ์…˜์„ ๋‹ซ์•„์ค๋‹ˆ๋‹ค.
์ถ”์ƒํ™”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ชจ๋“  ๊ตฌํ˜„์ฒด๋Š” ์ด ์ „๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.

 

๋งˆ์ง€๋ง‰์œผ๋กœ ๊ทธ๋ฆผ์„ ํ†ตํ•ด ์ „์ฒด์ ์ธ ๋™์ž‘ํ๋ฆ„์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

1. ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘

1-1. ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ transactionManager.getTransaction()์„ ํ˜ธ์ถœํ•ด ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘.

1-2. ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์—์„œ datasource๋ฅผ ์‚ฌ์šฉํ•ด ์ปค๋„ฅ์…˜ ์ƒ์„ฑ.

1-3. ์ปค๋„ฅ์…˜์„ ์ˆ˜๋™ ์ปค๋ฐ‹ ๋ชจ๋“œ๋กœ ๋ณ€๊ฒฝํ•ด์„œ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘.

1-4. ์ปค๋„ฅ์…˜์€ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์— ๋ณด๊ด€.

1-5. ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋Š” ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์— ์ปค๋„ฅ์…˜์„ ๋ณด๊ด€.

 

2. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง

2-1. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋กœ์ง์„ ํ˜ธ์ถœ.

2-2. ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต์—์„œ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์—์„œ ๋™๊ธฐํ™”๋œ ์ปค๋„ฅ์…˜์„ ์กฐํšŒ.

2-3. ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์—์„œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ณ„์ธต์— ์ปค๋„ฅ์…˜์„ ๋˜์ ธ์ค๋‹ˆ๋‹ค.

2-4. ์ปค๋„ฅ์…˜์„ ๊ธฐ๋ฐ˜์œผ๋กœ SQL๋ฌธ์„ ์‹คํ–‰.

 

3. ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ

3-1. ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๊ฑฐ๋‚˜ ๋กค๋ฐฑํ•จ์œผ๋กœ์จ ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ

3-2. ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์—์„œ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €๋กœ๋ถ€ํ„ฐ ๋™๊ธฐํ™”๋œ ์ปค๋„ฅ์…˜์„ ํš๋“

3-3. ํš๋“ํ•œ ์ปค๋„ฅ์…˜์„ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ or ๋กค๋ฐฑํ•ฉ๋‹ˆ๋‹ค

3-4. ์ „์ฒด ๋ฆฌ์†Œ์Šค(ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์˜ ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ ์ •๋ฆฌ, con.setAutoCommit(true)๋กœ ๋ณ€๊ฒฝ, con.close() ํ˜ธ์ถœ)๋ฅผ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

 

์ •๋ฆฌํ•ด๋ณด๋ฉด

  • ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” ๋•๋ถ„์— ์ด์ œ JDBC ๊ธฐ์ˆ ์— ์˜์กดํ•˜์ง€ ์•Š์•„ JDBC์—์„œ JPA๋กœ ๋ณ€๊ฒฝํ•ด๋„ ์„œ๋น„์Šค ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (๊ธฐ์ˆ  ๋ณ€๊ฒฝ์‹œ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…๋งŒ DataSourceTransactionManager์—์„œ JpaTransactionManager๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋จ)
  • ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ € ๋•๋ถ„์— ์ปค๋„ฅ์…˜์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธฐ์ง€ ์•Š์•„๋„ ๋˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์œ„์— ๊ธฐ์ˆ ํ–ˆ๋˜ 1๋ฒˆ ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐํ–ˆ๋Š”๋ฐ์š”. ์•„์ง  2๋ฒˆ JDBC ๋ฐ˜๋ณต ๋ฌธ์ œ์™€ 3๋ฒˆ ์˜ˆ์™ธ๋ˆ„์ˆ˜ ๋ฌธ์ œ๊ฐ€ ๋‚จ์•˜์Šต๋‹ˆ๋‹ค. 

Sol2. ํŠธ๋žœ์žญ์…˜ ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ 

Sol1์˜ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•œ ์„œ๋น„์Šค๊ณ„์ธต ์‚ดํŽด๋ณด๋ฉด 

public void accountTransfer(String fromId, String toId, int money) throws SQLException {

    // ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
    // ์ปค๋„ฅ์…˜ ์ƒ์„ฑ
    TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

    try
    {
        buisnesslogic(fromId, toId, money);
        transactionManager.commit(status);
    } catch (Exception e) {
        log.error("error detected!");
        transactionManager.rollback(status);
        throw new IllegalStateException(e);
    } // release๋Š” transactionManager๊ฐ€ ์•Œ์•„์„œ ํ•ด์คŒ.
}

try-catch-finally ํ˜•ํƒœ ๋‚ด์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ , ์ปค๋ฐ‹/๋กค๋ฐฑํ•˜๋Š”๋ฐ ์ด๋Ÿฐ ํ˜•ํƒœ๊ฐ€ ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ๋ฐ˜๋ณต๋˜์ง€ ์•Š๊ฒŒ ์Šคํ”„๋ง์ด ์ง€์›ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด(TransactionTemplate)์„ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

ํŠธ๋žœ์žญ์…˜ ํ…œํ”Œ๋ฆฟ ํด๋ž˜์Šค

public class TransactionTemplate {
      private PlatformTransactionManager transactionManager;
      public <T> T execute(TransactionCallback<T> action){..}
      void executeWithoutResult(Consumer<TransactionStatus> action){..}
  }
  • excute() : ์‘๋‹ต๊ฐ’์ด ์žˆ์„ ๋•Œ ์‚ฌ์šฉ
  • executeWithoutResult() : ์‘๋‹ต๊ฐ’์ด ์—†์„ ๋•Œ ์‚ฌ์šฉ

์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ์ด ํ…œํ”Œ๋ฆฟ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Slf4j
public class MemberServiceV3_2 {

//    private final PlatformTransactionManager transactionManager;
    private final TransactionTemplate txTemplate;
    private final MemberRepositoryV3 memberRepository;

    public MemberServiceV3_2(PlatformTransactionManager transactionManager, MemberRepositoryV3 memberRepository)
    {
        this.txTemplate = new TransactionTemplate(transactionManager);
        this.memberRepository = memberRepository;
    }

    public void accountTransfer(String fromId, String toId, int money) throws SQLException {

        // ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
        // ์ปค๋„ฅ์…˜ ์ƒ์„ฑ
//        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        txTemplate.executeWithoutResult((status)-> {
            try
            {
                buisnesslogic(fromId,toId,money);
            } catch (SQLException e) {
                throw new IllegalStateException(e);
            }
        });
    }
  • TransactionTemplate์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด transactionManager๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒ์„ฑ์ž์—์„œ transactionManager๋ฅผ ์ฃผ์ž…๋ฐ›์œผ๋ฉด์„œ ํ…œํ”Œ๋ฆฟ์„ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
  • try-catch๋ฅผ ๋ณด๋ฉด ํŠธ๋žœ์žญ์…˜์„ ์ƒ์„ฑํ•˜๊ณ , ์ปค๋ฐ‹/๋กค๋ฐฑํ•˜๋Š” ๋ถ€๋ถ„๋“ค์ด ํ…œํ”Œ๋ฆฟ์„ ํ†ตํ•ด ์‹คํ–‰ํ•จ์œผ๋กœ์จ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜ ํ…œํ”Œ๋ฆฟ์˜ ๊ธฐ๋ณธ๋™์ž‘
    • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์ •์ƒ ์ˆ˜ํ–‰๋˜๋ฉด ์ปค๋ฐ‹.
    • Uncheck ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋กค๋ฐฑ. check ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ปค๋ฐ‹.
    • ์ฝ”๋“œ์—์„œ ์—์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด try-catch๊ฐ€ ๋“ค์–ด๊ฐ”๋Š”๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค๋กœ์ง ์ˆ˜ํ–‰์ค‘ SQLException ์ฒดํฌ ์˜ˆ์™ธ๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š”๋ฐ, ํ•ด๋‹น ๋žŒ๋‹ค์—์„œ ์ฒดํฌ ์ฒดํฌ ์˜ˆ์™ธ๋ฅผ ๋ฐ–์œผ๋กœ ๋˜์งˆ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์ฒดํฌ ์˜ˆ์™ธ(IllegalStateException)๋กœ ๋ฐ”๊พธ์–ด ๋˜์ง€๋„๋ก ์˜ˆ์™ธ๋ฅผ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

<์ •๋ฆฌ> 

  • ํŠธ๋žœ์žญ์…˜ ํ…œํ”Œ๋ฆฟ ๋•๋ถ„์— ์ปค๋ฐ‹, ๋กค๋ฐฑ ์ž‘์—…์„ ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์ด๊ณณ์€ ์„œ๋น„์Šค ๊ณ„์ธต์ธ๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŠธ๋žœ์žญ์…˜์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ธฐ์ˆ ๋กœ์ง์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด ์ˆœ์ˆ˜ํ•œ ์„œ๋น„์Šค ๊ณ„์ธต์ด๋ผ๊ณ  ๋ณด๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  • ์„œ๋น„์Šค ๋กœ์ง์—๋Š” ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋งŒ ์žˆ์–ด์•ผ ํ•˜์ง€๋งŒ ํŠธ๋žœ์žญ์…˜ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์–ด์ฉ” ์ˆ˜ ์—†์ด ํŠธ๋žœ์žญ์…˜ ์ฝ”๋“œ๊ฐ€ ๋‚˜์™€์•ผ ํ•˜๋Š” ๋”œ๋ ˆ๋งˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ํŠธ๋žœ์žญ์…˜ AOP๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๊ฒฐํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

<์ฐธ๊ณ ์ž๋ฃŒ>

 

์Šคํ”„๋ง DB 1ํŽธ - ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ํ•ต์‹ฌ ์›๋ฆฌ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ DB ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ธฐ์ˆ ์„ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ดํ•ดํ•˜๊ณ , ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์Šคํ”„๋ง DB ์ ‘๊ทผ ๊ธฐ์ˆ ์˜ ์›๋ฆฌ์™€ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๊ณ , ๋” ๊นŠ์ด์žˆ๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜

www.inflearn.com

 

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

Study Repository

rlaehddnd0422

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