Hyo Kim
์ผ๋‹จ์€ ๋‚ด ์ด์•ผ๊ธฐ
Hyo Kim
์ „์ฒด ๋ฐฉ๋ฌธ์ž
61,464
์˜ค๋Š˜
23
์–ด์ œ
102
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (117) N
    • JVM (58)
      • Java (24)
      • Kotlin (3)
      • Spring (25)
      • JPA (6)
    • JavaScript (18)
      • JavaScript (12)
      • NodeJs (3)
      • React (1)
    • DataBase (12)
    • DevOps (2)
    • Network (2)
    • Tools (6)
    • HisStory (12) N
      • ๋‚˜๋Š”๋ฆฌ๋ทฐ์–ด๋‹ค2023 (1) N
    • Algorithm (1)
    • OS (2)
    • ProductiveWork (1)
    • Project (3)

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • ํ™ˆ
  • ํƒœ๊ทธ
  • ๋ฐฉ๋ช…๋ก

์ธ๊ธฐ ๊ธ€

  • [Java] Gradle, Groovy Gradle, Koโ‹ฏ
    2022.06.02
    [Java] Gradle, Groovy Gradle, Koโ‹ฏ
  • [Redis] ๋ ˆ๋””์Šค ์„ ํƒํ•˜๋Š” ์ด์œ 
    2022.06.16
    [Redis] ๋ ˆ๋””์Šค ์„ ํƒํ•˜๋Š” ์ด์œ 
  • [JAVA+MSSQL]๋“œ๋ผ์ด๋ฒ„๊ฐ€ SSL(Secure Socโ‹ฏ
    2021.07.18
  • [JavaScript]๋‘ ๋ฐฐ์—ด ์•ˆ์— ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋น„๊ต ํ›„ ์ค‘โ‹ฏ
    2020.12.13
    [JavaScript]๋‘ ๋ฐฐ์—ด ์•ˆ์— ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋น„๊ต ํ›„ ์ค‘โ‹ฏ
  • [Java] Random๋ณด๋‹จ SecureRandom ๋ฅผ ์‚ฌโ‹ฏ
    2021.06.06
    [Java] Random๋ณด๋‹จ SecureRandom ๋ฅผ ์‚ฌโ‹ฏ

์ตœ๊ทผ ๊ธ€

  • [๋‚˜๋Š”๋ฆฌ๋ทฐ์–ด๋‹ค] 2023 ๋ฆฌ๋ทฐ์–ด ์„ ์ •!
    2023.02.04
    [๋‚˜๋Š”๋ฆฌ๋ทฐ์–ด๋‹ค] 2023 ๋ฆฌ๋ทฐ์–ด ์„ ์ •!
  • [Gradle] ๋ฒ„์ „ ๋ณ„ Java, Kotlin ํ˜ธํ™˜ ๋ฒ„์ „โ‹ฏ
    2023.02.01
    [Gradle] ๋ฒ„์ „ ๋ณ„ Java, Kotlin ํ˜ธํ™˜ ๋ฒ„์ „โ‹ฏ
  • [Spring] h2 ์„ค์ •
    2023.01.29
    [Spring] h2 ์„ค์ •
  • 2022๋…„ ํšŒ๊ณ  ๅ‰ฏ้กŒ - ๊ฐ€์žฅ ์˜ค๋ž˜ ๊ธฐ์–ต ๋‚จ์„ ํ•œ ํ•ด Paโ‹ฏ
    2023.01.16
    2022๋…„ ํšŒ๊ณ  ๅ‰ฏ้กŒ - ๊ฐ€์žฅ ์˜ค๋ž˜ ๊ธฐ์–ต ๋‚จ์„ ํ•œ ํ•ด Paโ‹ฏ
  • [DataBase] CLI์—์„œ ์ฟผ๋ฆฌํ•  ๋•Œ๋„ ํŠธ๋žœ์žญ์…˜์„ ์“ฐ์ž
    2023.01.15

ํ‹ฐ์Šคํ† ๋ฆฌ

ํƒœ๊ทธ

  • JPA
  • JS
  • ์ž๋ฐ”
  • sql
  • Kotlin
  • transactional
  • querydsl
  • java
  • java8
  • Spring
  • Feign
  • springcloud
  • JAVA11
  • GraphQL
  • springboot
  • nodeJS
  • mssql
  • gradle
  • javascript
  • MySQL
๋ฐ˜์‘ํ˜•
250x250
hELLO ยท Designed By ์ •์ƒ์šฐ.
Hyo Kim

์ผ๋‹จ์€ ๋‚ด ์ด์•ผ๊ธฐ

JVM/Spring

[SPRING] synchronized์™€ @Transactional ์„ ๋™์‹œ์— ์‚ฌ์šฉ ์‹œ ๋ฌธ์ œ์ 

2021. 8. 16. 17:27
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ˜—์„œ๋ก 

@Transactional ์–ด๋…ธํ…Œ์ด์…˜๊ณผ synchronized์„ ๋™์‹œ์— ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ์ˆ˜์ค€๊ณผ ๋ณ„๊ฐœ๋กœ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ๋™๊ธฐํ™”๋ฅผ ์ ์šฉ์‹œํ‚ค๊ณ  ์‹ถ์„ ๋•Œ.

ํ•˜์ง€๋งŒ, ํ•œ ๋ฉ”์†Œ๋“œ ์œ„์— ํ•ด๋‹น Transactional, Synchronized๋ฅผ ๋™์‹œ์— ์ ์šฉ ์‹œ

์›ํ•˜๋Š”๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

 

๊ทธ ์ด์œ ๋ฅผ ์•Œ์•„๋ณด์ž.


๐Ÿ˜Ž๋ณธ๋ก 

์•„๋ž˜ ์˜ˆ์‹œ๋Š” ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ ๋ฒˆ์—ญํ•˜์—ฌ ํ’€์–ด์„œ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿคจ๋ญ๊ฐ€ ๋ฌธ์ œ์ง€?

์ผ๋‹จ Synchronized๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ•œ ์“ฐ๋ ˆ๋“œ์—์„œ๋งŒ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ๋‹ค.

ํ•˜์ง€๋งŒ, ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์ด ์ •์˜๊ฐ€ ๋˜์–ด์žˆ๋‹ค๋ฉด ์ฒซ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋๋‚˜๊ธฐ ์ „ ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฐœ๋™ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๊ทธ ์ด์œ ๋ฅผ ์‚ดํŽด๋ณด์ž.

@Transactional
public synchronized void onRequest(Request request) {

    if (request.shouldAddBook()) {
        if (database.getByName(request.getBook().getName()) == null) {
            database.add(request.getBook());
        } else {
            throw new Exception("Cannot add book - book already exist");
        }
    } else if (request.shouldRemoveBook()) {
        if (database.getByName(request.getBook().getName()) != null) {
            removeBook();
        } else {
            throw new Exception("Cannot remove book - book doesn't exist");
        }
    }
}

(ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋Š” ์˜ˆ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ์ด๋ฉฐ, ์™„๋ฒฝํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.)

 

์œ„ ๋ฉ”์†Œ๋“œ๋Š” ๋™์ž‘ ๋ฐฉ์‹์€ ์ด๋ ‡๋‹ค.

1. ์ฑ…์„ ์ถ”๊ฐ€ํ•˜๋Š”๊ฐ€?
1-1. ํ•ด๋‹น ์ฑ…์ด๋ฆ„์ด db์— ์—†๋Š”๊ฐ€?
1-2. ์—†์œผ๋ฉด ์ถ”๊ฐ€
1-3. ์žˆ๋‹ค๋ฉด Exception

2. ์ฑ…์„ ์‚ญ์ œํ•˜๋Š”๊ฐ€?
2-1. ํ•ด๋‹น ์ฑ…์ด๋ฆ„์ด db์— ์žˆ๋Š”๊ฐ€?
2-2. ์žˆ๋‹ค๋ฉด ์‚ญ์ œ
2-3. ์—†๋‹ค๋ฉด Exception

๐Ÿ˜…์˜ˆ์ œ

๋™์ผํ•œ ์ œ๋ชฉ์˜ ์ฑ…์„ ์ œ๊ฑฐํ•˜๊ณ  ์ถ”๊ฐ€ํ•˜๋Š” ์ˆœ์„œ๋กœ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์ง„ํ–‰ํ•ด ๋ณด๊ฒ ๋‹ค.

1. Transactional, Synchronized ํ‚ค์›Œ๋“œ๊ฐ€ ์—†๋‹ค๋ฉด ?

Thread1: |---remove book--->

Thread2: |---add book--->

์ด๋Š” ์‚ญ์ œ๊ฐ€ ๋˜๊ธฐ ์ „์— ๊ฑฐ์˜ ๋™์‹œ์— ์ถ”๊ฐ€ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐœ๋™๋˜๋ฏ€๋กœ

๋™์ผํ•œ ์ด๋ฆ„์˜ book์ด db์— ์กด์žฌํ•˜๊ฑฐ๋‚˜ Exception์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

2. Synchronized๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€ ?

Thread1: |---remove book---> Thread2: |---add book--->

์œ„์™€ ๊ฐ™์ด ์‚ญ์ œ๊ฐ€ ๋๋‚œ ํ›„ ๋‹ค์Œ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด์„œ ์ฑ…์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

ํ•˜์ง€๋งŒ, ์šฐ๋ฆฌ์—๊ฒ ํŠธ๋žœ์žญ์…˜์ด ํ•„์š”ํ•˜๋‹ค.

 

3. Transactional์„ ์ ์šฉํ•œ๋‹ค๋ฉด ?

@Transactional ์–ด๋…ธํ…Œ์ด์…˜์€ AOP๋‹ค. ๊ณ ๋กœ ์ƒˆ๋กœ์šด ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋œ๋‹ค.

 

begin Transaction ---> method ---> commit Transaction

์œ„์™€ ๊ฐ™์ด ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ์‹ธ ๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์ „, ํ›„๋กœ ์ƒˆ๋กœ์šด ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค.

 

๊ทธ๋ ‡๋‹ค๋ฉด ์ œ๊ฑฐ, ์ถ”๊ฐ€๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ์–ด๋–ป๊ฒŒ ์–ด๋–ป๊ฒŒ ๋™์ž‘์„ ํ•˜๊ฒŒ ๋ ๊นŒ?

 

T1: |--Spring begins Transaction---> ---remove book---> ---Spring commits Transaction--->

T2: |--Spring begins Transaction---> ---add book---> ---Spring commits Transaction--->

ํŠธ๋žœ์žญ์…˜์„ ์ ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ฑฐ์˜ ๋™์‹œ์— ์ง„ํ–‰๋˜๊ฒŒ ๋œ๋‹ค.

์•ž์œผ๋กœ ์š”์•ฝํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
T1: |--B--|--R--|--C-->
T1: |--B--|--A--|--C-->

 

ํŠธ๋žœ์žญ์…˜์€ ๋™์ผํ•œ entity๋งŒ์„ ๋™์‹œ์— ์ˆ˜์ •ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ๋‹ค.

์ƒˆ๋กœ add๋˜๋Š” book์€ ๋‹ค๋ฅธ entity๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™์ด ๋  ๊ฒƒ์ด๋‹ค.

ํ•˜์ง€๋งŒ, ๋™์ผํ•œ ์ด๋ฆ„์˜ book์ด ๋™์‹œ์— db์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์‹œ๊ฐ„์ด ์กด์žฌํ•˜๊ฑฐ๋‚˜ Exception์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

4. Synchronized๊ณผ Transactional์„ ๋™์‹œ์— ์ ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ?

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

Spring์—์„œ ์ถ”๊ฐ€ํ•˜๋Š” Transactional ์ฝ”๋“œ๋Š” ๋™๊ธฐํ™”๋กœ ๊ฐ์‹ธ์ง„ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ๋ณ„๋„์˜ ์ฝ”๋“œ๋ผ๋Š” ์ ์ด๋‹ค.

๊ทธ๋กœ ์ธํ•ด ๋™๊ธฐํ™”๋œ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ข…๋ฃŒ๋œ ํ›„ commit ์ด ๋˜๊ธฐ ์ „ ์‹œ์ ์—์„œ ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ง„ํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

 

T1: |--B--|--R--|--C-->

T2: |--B---------|--A--|--C-->

 

์œ„์™€ ๊ฐ™์ด remove ๋ฉ”์†Œ๋“œ๊ฐ€ ๋๋‚œ ์‹œ์ ์—์„œ add ๋ฉ”์†Œ๋“œ๊ฐ€ ๋™์ž‘ํ•˜๊ฒŒ ๋˜๋ฉด

commits์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ์ „์— add ๋ฉ”์†Œ๋“œ๊ฐ€ ์ง„ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— Exception์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿค”์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜์ง€?

ํ˜„์žฌ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ฐฉ์‹์€ @Transactional์„ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— ๋จผ์ € Synchronized๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

public class SynchronizedService() {

	@Autowired
	private TransactionService transactionService;
    
	public synchronized void onRequest(Request request) {
		transactionService.onRequest(request);
	}
}

public class TransactionService() {

  @Transactional
  public void onRequest(Request request) {
      if (request.shouldAddBook()) {
          if (database.getByName(request.getBook().getName()) == null) {
              database.add(request.getBook());
          } else {
              throw new Exception("Cannot add book - book already exist");
          }
      } else if (request.shouldRemoveBook()) {
          if (database.getByName(request.getBook().getName()) != null) {
              removeBook();
          } else {
              throw new Exception("Cannot remove book - book doesn't exist");
          }
      }
  }
}

์œ„์™€ ๊ฐ™์ด synchronized ์•ˆ์—์„œ @Transactional ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด

์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.

T1: |--B--|--R--|--C-->T2: |--B--|--A--|--C-->


๊ฒ€์ƒ‰ํ•ด๋ณธ ๊ฒฐ๊ณผ ๊ฒฉ๋ฆฌ์ˆ˜์ค€์œผ๋กœ ํ•ด๊ฒฐํ•˜๋ผ๋Š” ๊ธ€์„ ๋ช‡๋ช‡ ์ ‘ํ•˜๊ธด ํ•˜์˜€๋‹ค.

ํ•˜์ง€๋งŒ, ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ์ˆ˜์ค€์œผ๋กœ ์กฐ์ ˆํ•˜๋Š” ๊ฒƒ์€ ๋ฐ์ดํ„ฐ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ์œ„ํ•ด์„œ์ด๋‹ค.

์ด๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฒฉ๋ฆฌ์ˆ˜์ค€์„ ์กฐ์ ˆํ•˜๋Š” ๊ฒƒ์ด์ง€ synchronized์™€๋Š” ์ „ํ˜€ ๋‹ค๋ฅธ ์ ‘๊ทผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

์–ด๋А์ •๋„ ๊ฒฉ๋ฆฌ์ˆ˜์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ž ๊ถˆ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ,

์ด๋Š” ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉํ–ฅ๊ณผ๋Š” ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์™„๋ฒฝํ•˜๊ฒŒ ๊ฐ™์€ ๋™์ž‘์„ ์ด๋ค„๋‚ด์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

 

 

๋” ์ข‹์€ ๋ฐฉ์‹์ด๋‚˜ ์ž˜๋ชป๋œ ์ ์ด ์žˆ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. (__)

 

์ฐธ์กฐ

https://stackoverflow.com/questions/41767860/spring-transactional-with-synchronized-keyword-doesnt-work
https://stackoverflow.com/questions/6479283/logical-comparison-of-java-synchronized-keyword-and-spring-transactional-annota
https://github.com/Gluewine/Gluewine/issues/25
728x90
๋ฐ˜์‘ํ˜•

'JVM > Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[SPRING] ์Šคํ”„๋ง์˜ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์–ด๋–ป๊ฒŒ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ• ๊นŒ?  (0) 2021.11.15
[SPRING] @Transactional readOnly ์„ฑ๋Šฅํ–ฅ์ƒ ์ด์œ   (0) 2021.09.05
[SPRING] AOP ์šฐ์„ ์ˆœ์œ„ ์„ค์ •ํ•˜๊ธฐ.  (0) 2021.08.14
[SPRING] @Transactional (ํŠธ๋žœ์žญ์…˜) ๊ฐ•์ œ ๋กค๋ฐฑ  (0) 2021.07.25
[SPRING] Spring AOP Proxy - @Transactonal ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ  (0) 2021.07.25
    'JVM/Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
    • [SPRING] ์Šคํ”„๋ง์˜ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์–ด๋–ป๊ฒŒ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ• ๊นŒ?
    • [SPRING] @Transactional readOnly ์„ฑ๋Šฅํ–ฅ์ƒ ์ด์œ 
    • [SPRING] AOP ์šฐ์„ ์ˆœ์œ„ ์„ค์ •ํ•˜๊ธฐ.
    • [SPRING] @Transactional (ํŠธ๋žœ์žญ์…˜) ๊ฐ•์ œ ๋กค๋ฐฑ
    java, Spring, Spring boot, synchronized, Transaction, transactional
    Hyo Kim
    Hyo Kim
    ์„ฑ์žฅํ†ต์„ ๊ฒช๋Š” Level 1.5 ๋…„์ฐจ ๊ฐœ๋ฐœ์ž
    ๋Œ“๊ธ€์“ฐ๊ธฐ
    ๋‹ค์Œ ๊ธ€
    [SPRING] @Transactional readOnly ์„ฑ๋Šฅํ–ฅ์ƒ ์ด์œ 
    [SPRING] AOP ์šฐ์„ ์ˆœ์œ„ ์„ค์ •ํ•˜๊ธฐ.
    ์ด์ „ ๊ธ€
    [SPRING] AOP ์šฐ์„ ์ˆœ์œ„ ์„ค์ •ํ•˜๊ธฐ.

    ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”