3 minute read

남궁성님의 스프링 정석 : 남궁성과 끝까지 간다를 정리한 내용입니다.

0. 차례

  1. Transaction
  2. AOP
  3. @Transactional

    1. Transaction

    1-1. 트랜잭션이란?

    먼저 Transaction 이 무엇인지 알아보자.

트랜잭션(Transaction)이란
간단히는 더이상 나눌 수 없는 작업의 단위
데이터베이스에서 논리적 상태 변화, 즉 Insert, Update, Delet로 데이터베이스의 데이터가 변화가 있는 것을 트랜잭션이라 한다.
데이터의 변화가 많은 테이블을 트랜잭션 테이블이라 하고, 그렇지 않은 것을 마스터 테이블이라 한다.

1-2. 트랜잭션의 속성 (ACID)

  • Atomicity(원자성)
    • 나눌수 없는 하나의 작업으로 이루어져야 한다 .
  • Consistency(일관성)
    • Tx 수행 전과 후가 일관된 상태를 유지해야한다.
  • Isolation(고립성)
    • 각 Tx는 독립적으로 수행되어야 한다.
    • Isolation Level 을 적절히 조절해야 한다.
  • Durability(영속성)
    • 성공한 Tx의 결과는 유지되어야 한다.

1-3. 커밋과 롤백

  • Commit(커밋)
    • 작업한 내용을 DB에 영구히 저장한다.
    • 자동커밋
      • Default 값이 1 이다.
      • 명령 실행 후, 자동으로 커밋이 수행 (rollback 불가)
    • 수동커밋
      • Set autocommit (0) 을 통해 변경
      • 명령 실행 후, 명시적으로 commit 또는 rollback 을 입력
  • Lollback(롤백)
    • 최근 변경 사항을 취소(마지막 커밋으로 복귀)

1-4. Tx의 Isolation Level

아래 4개의 격리수준중 아래로 갈수록 트랜잭션 간의 데이터 격리(고립) 정도가 높아지며, 동시성 처리 성능이 떨어진다.

  1. READ UNCOMMITED
    • 커밋되지 않은 데이터도 읽기 가능
    • Dirty Reead 발생
      • 다른사람이 손을 대서 더러워짐을 뜻함,,
      • 더티 리드란 다른 트랜잭션에서 처리한 작업이 완료되지 않았음에도, 다른 트랜잭션에서 볼수 있게 되는 현상을 말한다.
  2. READ COMMITTED
    • Phantom Read 발생
    • 커밋된 데이터만 읽기 가능
    • 온라인 서비스에서 가장 많이 사용되는 격리수준
    • NON-REPEATABLE READ 발생
      • 하나의 트랜잭션 내에서 동일한 SELECT 쿼리를 실행했을 때 항상 같은 결과를 보장해야 한다는 REPEATABLE READ 정합성에 어근사는 것을 말함
    • 오라클 기본 격리수준
  3. REPEATABLE READ (기본값)
    • Tx이 시작된 이후 변경은 무시된다.
    • 반복해서 읽기 가능
    • InnoDb 스토리지 엔진 기본 격리 수준
    • Phantom Read 발생
      • 첫 번째 쿼리에서는 없었던 레코드가 두분째 쿼리에서는 존재하는 것처럼 보이는 현상을 말한다. (Repeatable Read 나 ReadCommited 격리 수준에서 발생할 수 있음)
  4. SERIALIZBLE
    • 격리수준이 가장 높음
    • 한번에 하나의 Tx만 독립적으로 수행.
    • 직렬 처리를 하여 데이터의 일관성과 무결성을 보장할 수 있지만, 서비스 성능(처리량이 많은)이 많이 떨어진다.

1-5. Transaction Test

public void transcationTest() throws Exception {
    Connection conn = null;
    try {
        conn = ds.getConnection();
        conn.setAutoCommit(false); // auto commit 을 false 로 해두어라

        String sql = "insert into test (id, pw) values (?, ?)"; // id 는 pk

        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, "han");
        pstmt.setString(2, "sw");

        int rowCnt = pstmt.executeUpdate(); // insert, delete, update
        pstmt.setString(1, "han")
        rowCnt = pstmt.executeUpdate;
        conn.commit();
    } catch(Exception e) {
        conn.rollback();
    }
}

2. AOP

2-1. AOP란

AOP는 관점 지향 프로그래밍 (Aspect Oriented Programming)의 약자이다. 관점지향프로그래밍이라는 용어가 굉장히 어색하지만, 부가기능을(advice)를 동적으로 추가해주는 기술이라 생각하면된다. 코드의 메소드 시작 또는 끝에 자동으로 코드(advice)를 추가해주는 기술이다.

OOP 와 마찬가지로 AOP도 변경에 유리한 코드를 생성하기 위함이다. (분리)

AOP

2-2. AOP 직접 구현하기 example

import java.lang.reflect.Method;

public class AopMain {
    public static void main(String[] args) throws Exception {
        MyAdvice myAdvice = new MyAdvice();

        Class myClass = class.forName("com.test.aop.MyClasss");
        Object obj = myClass.newInstance();

        for (Method m : myClass.getDeclareMethods()) {
            myAdvice.invoke(m, obj, null);
        }
    }
}

public MyAdvice {
    void invoke(Method m, Object obj, Object... args) throws Excpetion {
        // 이곳에 여러가지 조건문을 통해, 출력 여부를 결정할수도 있다.
        // if(m.getAnnotation(Transactional.class)!=null)
        System.out.println("before{");
        m.invoke(obj, args);
        System.out.println("}after");
    }
}

public MyClass {
    void test1() {
        System.out.println("test1() is called");
    }

    void test2() {
        System.out.println("test2() is called");
    }
}

2-3. 코드를 자동으로 추가하려면, 어디에 추가해야 할까??

  • Before Advice: 메소드의 시작지점
  • After Advice: 메소드의 마지막 지점 (return 바로전)
  • Around Advice: 양쪽다

메소드의 중간지점엔 불가능하다.

2-4. AOP 관련 용어

|용어|설명| |—|—–| |target|advice가 추가될 객체| |advice|target에 동적으로 추가될 부가기능(코드)| |join point|advice가 추가(join)될 대상(메서드)| |pointcut|join poin들을 정의한 패턴| |proxy|target에 advice가 동적으로 추가되어 생성된 객체| |weaving|target에 advice를 추가해서 proxy를 생성하는 것|

(advice) + (target) + (advice) = proxy

2-5. Adivce의 종류

Adivce 설정은 XML과 @Annotaion 으로 설정 가능하다.

종류 어노테이션 설명
around advice @Around 메서드의 시작과 끝 부분에 추가되는 부가 기능
before advice @Before 메서드의 시작 부분에 추가되는 부가 기능
after advice @After 메서드의 끝 부분에 추가되는 부가기능
after returning @AfterReturning 예외가 발생하지 않았을 때, 실행되는 부가 기능
after throwing @AfterThrowing 예외가 발생했을 때, 실행되는 부가기능

2-6. AOP Example

dependency 추가

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
</dependency>

example code

public class LoggingAdvice {
    @Around("execution(* com.my.test.aop.*.*.(..))") // around 안에 pointcut 추가 - 부가기능이 적요될 메서드의 패턴
    public Object methodCallLog(ProceedingJoinPoint pjp) throws Throwable { // return 결과는 void 가능, ProceedingJoinPoint 는 메서드의 모든 정보를 불러올수 있다.
        long start = System.currentTimeMillis();
        System.out.println("start");
        
        Object result = pjp.proceed(); // target의 메서드 호출

        System.out.println("end" + (System.currentTimeMillis() - start) + "ms");
        return result; // 메서드가 여러곳에 적용될수 있으므로 메서드 호출겨로가를 반환한다.
    }
}

– 참고 데이터베이스 MySQL 트랜잭션 격리 수준

Categories:

Updated: