@Transactional

@Transactional ์ด๋ž€?

  • @Transactional์€ ํด๋ž˜์Šค๋‚˜ ๋ฉ”์„œ๋“œ์— ๋ถ™์—ฌ์ค„ ๊ฒฝ์šฐ, ํ•ด๋‹น ๋ฒ”์œ„ ๋‚ด ๋ฉ”์„œ๋“œ๊ฐ€ ํŠธ๋žœ์žญ์…˜์ด ๋˜๋„๋ก ๋ณด์žฅํ•ด์ค€๋‹ค

  • ์„ ์–ธ์  ํŠธ๋žœ์žญ์…˜์ด๋ผ๊ณ ๋„ ํ•˜๋Š”๋ฐ, ์ง์ ‘ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ํ•„์š” ์—†์ด ์„ ์–ธ๋งŒ์œผ๋กœ๋„ ๊ด€๋ฆฌ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

  • ํŠนํžˆ๋‚˜ SpringBoot์—์„œ๋Š” ์„ ์–ธ์  ํŠธ๋žœ์žญ์…˜์— ํ•„์š”ํ•œ ์—ฌ๋Ÿฌ ์„ค์ •์ด ์ด๋ฏธ ๋˜์–ด์žˆ์–ด ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค

@Transactional(readOnly=true)๊ฐ€ ๊ผญ ํ•„์š”ํ•œ๊ฐ€?

  • ์จ์ฃผ๋Š”๊ฒŒ ์ข‹๋‹ค!

  • why?

    • ์กฐํšŒํ•œ ๋ฐ์ดํ„ฐ๋ฅผ return ํ•œ๋‹ค๊ณ  ํ•ด๋„ ์˜๋„์น˜ ์•Š๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ์ผ์„ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•ด์ค€๋‹ค

      • ์˜ˆ์ƒ์น˜ ๋ชปํ•œ Entity์˜ ๋“ฑ๋ก, ๋ณ€๊ฒฝ, ์‚ญ์ œ ์˜ˆ๋ฐฉ

    • Entity๋ฅผ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์กฐํšŒ ์‹œ, ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ์œ„ํ•œ snapshot์„ ์œ ์ง€ํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ , ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ flush ํ•˜์ง€ ์•Š์•„๋„ ๋ผ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค

      • ํŠธ๋žœ์žญ์…˜์— readOnly=true ์˜ต์…˜์„ ์ฃผ๋ฉด ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ Hibernate session flush mode๋ฅผ MANUAL๋กœ ์„ค์ •ํ•œ๋‹ค

        • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ•์ œ๋กœ ํ”Œ๋Ÿฌ์‹œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ํ•œ ํ”Œ๋Ÿฌ์‹œ๊ฐ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค!

      • ๋”ฐ๋ผ์„œ ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๋”๋ผ๋„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ”Œ๋Ÿฌ์‹œ ๋˜์ง€ ์•Š์•„์„œ ์—”ํ‹ฐํ‹ฐ์˜ ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ์ด ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค

        • ๋˜ํ•œ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ์œ„ํ•œ ์Šค๋ƒ…์ƒท์„ ๋ณด๊ด€ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋œ๋‹ค

    • ํ•ด๋‹น ์˜ต์…˜์ธ ๊ฒฝ์šฐ CUD ์ž‘์—…์ด ๋™์ž‘ํ•˜์ง€ ์•Š๊ณ , ์Šค๋ƒ…์ƒท ์ €์žฅ, ๋ณ€๊ฒฝ ๊ฐ์ง€(dirty check)์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•„ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋œ๋‹ค

      • Dirty check ์ด๋ž€?

        • ์ƒํƒœ ๋ณ€๊ฒฝ๊ฒ€์‚ฌ

        • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ์—ฐ๊ฒฐ๋จ

          • JPA์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋Š” ์‹œ์ ์— ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ž๋™์œผ๋กœ ๋ฐ˜์˜ํ•ด์ค€๋‹ค

          • JPA์—์„œ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋ฉด ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ์˜ ์ฒ˜์Œ ์กฐํšŒ ์ƒํƒœ ๊ทธ๋Œ€๋กœ ์Šค๋ƒ…์ƒท์„ ๋งŒ๋“ค์–ด ๋†“๋Š”๋‹ค

          • ๊ทธ๋ฆฌ๊ณ  ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋Š” ์‹œ์ ์—๋Š” ์ด ์Šค๋ƒ…์ƒท๊ณผ ๋น„๊ตํ•ด์„œ ๋‹ค๋ฅธ ์ ์ด ์žˆ๋‹ค๋ฉด Update Query๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ์ „๋‹ฌํ•œ๋‹ค

    • MySQL ์ด์ค‘ํ™” ๊ตฌ์„ฑ(Master - Slave) ์‹œ DB๊ฐ€ master์™€ slave๋กœ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ๋‹ค๋ฉด readOnly = true๋กœ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ master๊ฐ€ ์•„๋‹Œ slave๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค

      • ์ƒํ™ฉ์— ๋”ฐ๋ผ DB ์„œ๋ฒ„์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ด๊ณ  ์•ฝ๊ฐ„์˜ ์ตœ์ ํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค

    • @Transactional(readOnly=true) annotation ์žˆ๋‹ค๋ฉด ์ฝ”๋“œ๋ฅผ ์ ‘ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ง๊ด€์ ์œผ๋กœ ๋ณด๊ธฐ์— ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” READ์— ๋Œ€ํ•œ ๋™์ž‘๋งŒ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค

Spring @Transactional vs javax @Transactional

  • javax @Transactional

    • ์ž๋ฐ” ํ‘œ์ค€ ํ™•์žฅ ํŒจํ‚ค์ง€

    • ์ž๋ฐ”์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต

  • Spring @Transactional

    • org.springframework์—์„œ ์ œ๊ณต

    • Spring Container๊ฐ€ ๊ด€๋ฆฌํ•ด์ค€๋‹ค

  • org.springframework.transaction.annotation.Transactional ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 

    • ๋งŽ์€ Option๋“ค์„ ์ œ๊ณตํ•œ๋‹ค

      • isolation: the underlying database isolation level

      • noRollbackFor and noRollbackForClassName: the list of Java Exception classes that can be triggered without triggering a transaction rollback

      • rollbackFor and rollbackForClassName: the list of Java Exception classes that trigger a transaction rollback when being thrown

      • propagation: the transaction propagation type given by the [Propagation](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html) Enum. For instance, if the transaction context can be inherited (e.g., REQUIRED) or a new transaction context should be created (e.g., REQUIRES_NEW) or if an exception should be thrown if no transaction context is present (e.g., MANDATORY) or if an exception should be thrown if a current transaction context is found (e.g., NOT_SUPPORTED).

      • readOnly: whether the current transaction should only read data without applying any changes.

      • timeout: how many seconds should the transaction context be allowed to run until a timeout exception is thrown.

      • value or transactionManager: the name of the Spring TransactionManager bean to be used when binding the transaction context.

Last updated

Was this helpful?