상세 컨텐츠

본문 제목

78일 - AOP, Proxy, @Transactional, ACID 中 1) 원자성 테스트

수업 일지/Spring

by NayC 2021. 6. 10. 12:22

본문

728x90

'주문'을 insert하는 서비스를 만든다고 해보자.

- 이때 사용되는 data는 하나가 아님

 

'결제' 서비스를 만든다고 해보자. 

- (사실 결제는 '주문' 테이블에 들어감)

- 결제 정보 입력 ... and? 

- 사용자가 결제할 때 포인트같은걸 썼을 수도

  -> 포인트, 쿠폰 사용에 대한 업데이트

  -> 포인트 up .... 등등등등

- '포인트 차감'이라고 하면 이것에 대한 것만(!) 되서는 안 됨. 

  전체가 다 되어야 함. (포인트 차감, 쿠폰 차감... 이런 것들이 '다')

 

구현 할 때는 어떻게? 

cf) 만약 jdbc 였다면 com.setAutoCommit(false) ... 안에다가 다 함수들 적어주고 com.commit();  해주면 된다고 생각할 수도 있으나 ... 이게 불가능하다. (각각 commit 된 상태라서)

con. (connection)을 공유하고 있어서

 

 

 

-> connection 의 이 문제를 해결한게 바로 EJB (서버임)

 

EJB에 Dao 등록 

Dao 생성은 EJB 서버가 생성

EJB 서버 안에 Container. 설정을 잘해줘야!! Dao가 다운되지 않고 잘 실행됨 (쉽게 다운된다고 함ㅠ)

- Dao를 EJB라고 하고 EJB 컨테이너 안에 올리는데 자꾸 다운된다고.... 

 

vs 우리가 만든 Dao는 심플. 

 

-> 그럼에도 불구하고 올려야하는 이유는 connection 때문 ㅠ 

    하나의 connection을 유지할 수 있도록 하게 / 그래서 물려서! 한 번에 처리해주는 트랜잭션을 위해... 

 

갈등... EJB 쓰자니 성능이 안 좋고, 안 쓰자니 또 그렇고...


AOP의 등장! 

유튜브에 영상 8개로 있음

 

AOP가 왜 필요한지만 이해하면 전혀 어렵지 않다.
모든 메소드의 호출 시간을 측정하고 싶다면?
- 상황 가정 : 초마다 다 코드 만들어놨는데 갑자기 상사가 ms로 바꾸라고 해서 다시 다 수정해야 하는 상황


메소드가 1억개라면? ...
... 이렇게 시간 찍는건 '핵심 기능'이 아님.
- 여러 메소드의 공통적인 문제임
공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)
- 시간 측정 : 공통 관심 사항
- 각 메소드들 : 핵심 관심 사항
이 둘이 섞여져 있어서 유지 보수가 정말 힘듦

출처 : https://ubermensch-with.tistory.com/394?category=938522

 

코드를 필요하면 꽂았다가, 필요하지 않으면 꽂아넣지 않도록 하기

-> AOP가 쉽게 해준다 :)

 

AOP 용어를 알아보자.

핵심 관심 사항 / 주업무 : core/primary concern (각 메소드들!) 

공통 관심 사항 / 부업무 : cross-cutting concern 

 

빵또아.

Q. 어떻게 한 번 만든걸 (공통핵심사항) 모든 함수의 빵또아의 빵 위치에 꽂을 수 있을까? 

 

Proxy 클래스를 둔다. 

- 그리고 cross-cutting concern 클래스 준비.

한 번 만들어 놓으면 되는거지~ :)

(빵또아 공장 느낌ㅎㅎ)

 

왼쪽 보라색 점은 '호출 함수' 어떤거든 main 함수든 (예를 들어 이 과정을 f1() 함수라고 하면) f1() 함수를 호출해주는 것

 

// 

 

예제

cross vs core 나눠주기! 

Q. proxy 자료형이 Exam인가? 

 

// 만들어보자.

 

javaPrj 

패키지명 com.newlecture.entity 

클래스 추가 - NewlecExam implements Exam

세팅해주고 (4단계)

 

3번째줄 이름 NewlecExam으로

패키지명 com.newlecture.entity

인터페이스 추가 - Exam 

package com.newlecture.entity;

public interface Exam {
	int total();
	float avg();
}
package com.newlecture.entity;

public class NewlecExam implements Exam {
	private int kor;
	private int eng;
	private int math;
	
	public int total() {
		
		int result = kor + eng + math;
		
		return result;
	}
	
	public float avg() {
		
		float result = total()/3.0f;
		
		return result;
	}
}

// AOP 전혀 염두해두지 않는다면

 

App에 main 함수 있는데 

Exam exam = new NewlecExam();

System.out.println(exam.total());

 

 

-> 실행하면 0이 나옴

 

// 스프링

'앞 뒤로 log를 남기고 싶다'면? 

-> Proxy 코드를 추가하자.

 

core를 흉내내는 가짜 클래스. 

NewlecExam을 똑 닮은 가짜 instance 생성 가능

- 진짜도 만들어줘야하고

- 흉내내서 사용할 수 있는 껍데기를 만들어주기도... 

- 핸들러같은것도 만들어줘야... 

 

가짜를 만들어보자! 

Exam exam = Proxy.newProxyInstance(null, null, null);

- exam은 가짜인지 찐짜인지를 모르고 호출하게 됨. 

 

Spring DI.

Proxy 생성하는데 훨씬 더 유연하게 해준다. 

 

class 정보를 통해서 

자료형에 맞는 인터페이스 정보를 줘야. new Class[] (Exam.class),

new InvocationHnadler <- 익명객체로 해주는 중... 

 

exam.total에서 exam은 가짜! 

30번째줄을 안해주면 null만 retrun하는거고, 이걸 해줘야함!! 

- 만약 이 위에 System.our.println("하하")를 입력 / 아래다가 "호호"를 하면 이게 빵 부분

- 이게 아이스크림 부분인 것! 

 

 

// AOP는 이 정도로


다시 아까 하던거로 돌아오면 ~ 

 

57 - 58번재줄 사이에 하나만 추가해주면 됨

-> @Transactional

 

Q. 트랜잭션을 처리한다는건? 4가지를 처리하는 것

-> ACID

A 원자성 - '원자성전파'에 대해 알아야. 

C 일관성 - 데이터 결함 발생하지 않도록

I 고립성 - 여러 요청 들어왔을 때 다른 사람의 개입 없이 하도록 

D 지속성 - 천재지변으로 전기가 나가도 내가 commit한 내용은 저장되어야

 

https://ubermensch-with.tistory.com/370

 

//

 

Dao 이용해서 2개 서비스 넣어보자. 

 

원자성 테스트

일부러 오류 내 본 상황

- wirterId를 실제 존재하지 않는걸 넣어준 것

- FK

 

서버 실행해서 -> 수정 -> update 하기 위해 '저장' 누르면 오류남

 

transaction이 깨졌는지가 포인트

hit가 100일가 0일까 

우리가 기대했던 값은 0.

- 억지로 2번의 update를 했잖아.

  2번의 update를 다 했다면 hit는 0이 되어야 하잖아. 

-> 그러니 잘못된 것 (지금 100 나왔으니)

 

취소가 되서 0이 되었어야 정상. (원래 0이었음)

- 실행하면 100 되면 안 됨.

- 오류나서 반쪽 날라간 상태인데... 

 

@Transactional 쓰면 (@Override 위에) 

-> 또 오류

 

콘솔창 결과 보기

-> 콘솔창에서는 아래처럼 나도 나오는데 0이 나오는걸 어떻게 확인하지? MySQL 들어가서 확인인가?

-> 그렇다.

 

92032880 (내가 실행한 id) 

 

원자성을 잘 지켜주는 중

- 오류면 -> 복구 해놔야

 

cf) 아까 100이 나온건 transation이 깨진거 (둘 다 안되면 다 안되어야지)

 

@Transactional 안 썼을 때는 

-> 100이 삽임됨

이러면 지금 원자성 '위반' 되는것. 안 되면 다 안되어야지. 


update 지금 2개지 (일부러 오류내도록 써준거는 주석처리)

 

MyBatisNoticeDao를 가보자.

요지는! NoticeDao에서도 2개 같이 해줘야할 상황이 있을 수 있겠구나~ 

 

NoticeServiceImp

@트랜잭션 

-> 지켜짐 (에러가 나면 원래대로 돌아감)

 

Q. 둘 중 뭘까? 트랜잭션 유지될까? 

1. 원래대로 돌아간다 (hit=1)

2. 아래단에서 나는 오류는 상관없다. 그래서 hit=200 나올것이다. 

 

100, 200 나오는게 최악이지 (원자성 위반되는거니까)

확인은... 두둥! 

// 

 

아래단에서의 트랜잭션도 다 처리.... OK.

 

근데 만약 아래단에서 '나한테 신경쓰지마!' 하는 옵션도 있다. 

이건 내일! 

 

 

 

 

 

728x90
반응형

관련글 더보기