Transaction / RESTful

์ด๋™์–ธยท2024๋…„ 9์›” 3์ผ

new world

๋ชฉ๋ก ๋ณด๊ธฐ
38/62
post-thumbnail

9.3 (ํ™”)

1. AOP

๐Ÿ“Œ Target : ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋งŒ๋“  ์ฝ”๋“œ
๐Ÿ“Œ Proxy : Target์„ ๊ฐ์‹ธ๊ณ ์žˆ๋Š” ๊ฐ์ฒด
๐Ÿ“Œ aspect : logging, transaction๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์ž์ฒด๋ฅผ ์˜๋ฏธ
๐Ÿ“Œ advice : ์‹ค์ฒด, ํšก๋‹จ๊ด€์‹ฌ์‚ฌ ์ฝ”๋“œ(aspect๋ฅผ ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ)

๐Ÿ“Œ AOP์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ๋Š” @Before / @Around๊ฐ€ ์žˆ๋Š”๋ฐ

๐Ÿ‘‰ @Before๋Š” ๋ฉ”์†Œ๋“œ์˜ ์ด๋ฆ„์„ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.
๐Ÿ‘‰ @Around๋Š” ๊ฑธ๋ฆฐ์‹œ๊ฐ„์„ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

package org.zerock.w2.aop;

@Aspect
@Component
@Log4j2
public class LogAdvice {

    @Before("execution(* org.zerock.w2.service.*.*(..))")
    // execution ๋‚ด๋ถ€ ์ฝ”๋“œ๋Š” service ์•„๋ž˜์˜ ๋ชจ๋“  ๋ฉ”์†Œ๋“œ๋“ค์€ ํ•ด๋‹น logBefore ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฑฐ์ณ๊ฐ„๋‹ค.
    public void logBefore(JoinPoint joinPoint) {
        log.info("-------------------------");
        log.info("-------------------------");

        log.info(Arrays.toString(joinPoint.getArgs()));

        log.info("-------------------------");
        log.info("-------------------------");
    }

    @Around("execution(* org.zerock.w2.service.*.*(..))")
    public Object logBefore(ProceedingJoinPoint joinPoint) throws Throwable {

        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long end = System.currentTimeMillis();

        log.info("TIME: "+ (end-start));

        return result;
    }
}

๐Ÿ‘‰ JoinPoint joinPoint๋Š” ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋กœ, ๋ฉ”์„œ๋“œ์ด๋ฆ„, ๋งค๊ฐœ๋ณ€์ˆ˜๋“ฑ๊ณผ ๊ฐ™์€ ์—ฌ๋Ÿฌ ์ •๋ณด๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
๐Ÿ‘‰ joinPoint.getArgs()๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ๋ฉ”์„œ๋“œ์˜ ์ธ์ž๋“ค์„ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๊ฐ€์ ธ์˜จ ํ›„, ์ด๋ฅผ Arrays.toString()์œผ๋กœ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋กœ๊ทธ์— ๊ธฐ๋กํ•œ๋‹ค.

๐Ÿ‘‰ joinPoint.proceed()๋ฅผ ํ†ตํ•ด ์‹ค์ œ ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ result์— ์ €์žฅ
๐Ÿ‘‰ ์‹ค์ œ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋จ์— ๋”ฐ๋ผ ์‹œ์ž‘์‹œ๊ฐ„๊ณผ ์ข…๋ฃŒ์‹œ๊ฐ„์„ ํŒŒ์•…ํ•˜์—ฌ ๋ฉ”์„œ๋“œ ์‹คํ–‰์‹œ๊ฐ„์„ ํŒŒ์•… ํ•  ์ˆ˜ ์žˆ๋‹ค.




2. Transaction

๐Ÿ‘‰ ๋‘๊ฐ€์ง€์˜ ์ผ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ / Service์—์„œ๋Š” ๋ฌด์กฐ๊ฑด ์‚ฌ์šฉํ•ด์•ผํ•˜๊ณ , ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•ด์ค˜์•ผํ•œ๋‹ค.

๐Ÿ“Œ ์˜ˆ๋ฅผ๋“ค์–ด, db์— table_a (varchar(10)), table_b (varchar(2))๊ฐ€ ์žˆ์„๋•Œ, service์™€ ์ปจํŠธ๋กค๋Ÿฌ,mapper ๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ ํ…Œ์ด๋ธ”์— ๋ฌธ์ž์˜ ๊ธธ์ด๊ฐ€ 5์ธ sql๋ฌธ์„ insertํ•˜๋ ค๊ณ ํ•œ๋‹ค. aํ…Œ์ด๋ธ”์—๋Š” ๊ธธ์ด๊ฐ€ ์ ํ•ฉํ•˜์ง€๋งŒ, bํ…Œ์ด๋ธ”์—๋Š” ๊ธธ์ด๊ฐ€ ์ ํ•ฉํ•˜์ง€ ๋ชปํ•œ์ƒํƒœ์ด๋‹ค. ์ด๋•Œ ๊ทธ๋ƒฅ ํ‰์†Œ์‚ฌ์šฉํ•˜๋“ฏ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ์ด ๋˜์ง€๋งŒ ๊ฒฐ๊ณผ์ ์œผ๋กœ aํ…Œ์ด๋ธ”์—๋Š” insert๊ฐ€ ๋˜์ง€๋งŒ bํ…Œ์ด๋ธ”์—๋Š” insert๊ฐ€ ๋˜์ง€์•Š๋Š”๋‹ค.

๐Ÿ“Œ ํ•˜์ง€๋งŒ, service ๋ถ€๋ถ„์— @Transactional ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด aํ…Œ์ด๋ธ”์—๋Š” insert๊ฐ€ ๋˜๊ณ  bํ…Œ์ด๋ธ”์—๋Š” insert๊ฐ€ ๋˜๋ ค๋‹ค ์‹คํŒจ๋ฅผ ํ•ด์„œ aํ…Œ์ด๋ธ”์˜ insert๊ฐ’์ด rollback๋˜์–ด ๋‘ ํ…Œ์ด๋ธ” ๋ชจ๋‘ insert๋˜์ง€ ์•Š๋Š”๋‹ค.


2-1. root-context.xml ๋‚ด๋ถ€์— transactionManager, tx:annotation ์ถ”๊ฐ€

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
  
  <tx:annotation-driven></tx:annotation-driven>

2-2.

๐Ÿ‘‰ select๋ฌธ์—์„œ๋Š” readOnly = ture๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™” ์‹œํ‚ฌ์ˆ˜์žˆ๋‹ค. (์ฝ๊ธฐ์ „์šฉ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š”๊ฒƒ์ด๋ฏ€๋กœ)




3. RestController (json ๋ฐ์ดํ„ฐ๋ฐ›๊ธฐ)

3-1. gradle ์ถ”๊ฐ€

implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2'

3-2. ReplyController

package org.zerock.w2.controller;

import lombok.extern.log4j.Log4j2;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.w2.vo.ReplyVO;

@RestController // ์ž๋™์œผ๋กœ json์œผ๋กœ ๋ณ€ํ™˜
@RequestMapping("/reply")
@Log4j2
public class ReplyController {

    @PostMapping(value = "")
    public ResponseEntity<ReplyVO> register( // ReplyVO๋ฅผ JSONํ˜•์‹์œผ๋กœ ๋ฐ›๊ณ 
            @RequestBody ReplyVO replyVO) {
            // requestBody๋ฅผ ํ†ตํ•ด JSONํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ReplyVO ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜

        log.info("Reply vo: "+ replyVO);

        // 200 ok ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”
        return ResponseEntity.ok(replyVO);
    }

}

3-3. JSON์˜ ๋‹จ์ 
๐Ÿ‘‰ ๊ทœ๊ฒฉํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค.




4. PK,FK

๐Ÿ“Œ PK
๐Ÿ‘‰ ๋…ผ๋ฆฌ์ ์˜๋ฏธ : ์‹๋ณ„๊ฐ’, ์œ ๋‹ˆํฌ
๐Ÿ‘‰ ๋ฌผ๋ฆฌ์ ์˜๋ฏธ : ์ธ๋ฑ์Šค (์†๋„)

๐Ÿ“Œ FK
๐Ÿ‘‰ ๊ฒŒ์‹œ๊ธ€ - ๋Œ“๊ธ€ ํ…Œ์ด๋ธ”์˜ ๊ด€๊ณ„์—์„œ, 1๋ฒˆ ๊ฒŒ์‹œ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ ๋Œ“๊ธ€์ด ์žˆ์„๋•Œ, 1๋ฒˆ ๊ฒŒ์‹œ๊ธ€์ด ์—†์–ด์ง€๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ๋Œ“๊ธ€๋“ค์€ ์˜๋ฏธ๊ฐ€ ์—†์–ด์ง€๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด FK๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

alter table tbl_reply
    add constraint fk_board_reply foreign key (bno)
    references tbl_board(bno)
;

๐Ÿ‘‰ ๊ฒŒ์‹œ๊ธ€์˜ pk์ธ bno๋ฅผ ๋Œ“๊ธ€ ํ…Œ์ด๋ธ”์—์„œ fk๋กœ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ

0๊ฐœ์˜ ๋Œ“๊ธ€