Study/Spring

[Spring Framework] 트랜잭션 관리

AC 2019. 8. 3. 22:54

 

트랜잭션이란 간단히 말해 처리 단위이다.


예를 들면, 웹 사이트에서 검색하고 상품 목록을 보기까지의 트랜잭션, 웹 사이트에서 상품을 주문해서 상품이 집에 도착하기까지처럼 긴 트랜잭션, 주문을 받고 발주 테이블과 고객테이블, 재고 테이블을 갱신하는 데이터베이스 트랜잭션 등이 있따. 여기서는 그중 데이터베이스 트랜잭션을 다루지만, 이처럼 다양한 트랜잭션이 있다는 점을 기억해야 한다.

이 트랜잭션에는 지켜야 할 ACID라는 특성이 있다. 이 중에서 애플리케이션 아키텍처로서 신경을 써야하는 것은 원자성(atomicty), 독립성(isolation)이다.

반면, 영속성(durability)은 우리가 만드는 애플리케이션의 전제 조건이라고 할 수 있다.(애플리케이션에서 어떻게 영속성을 보증할 것인가?)

 

시스템을 구축할 때는 원자성의 범위를 정해야 한다.
모든 처리가 실행됐는지, 실행되지 않았는지 처리 단위(트랜잭션)를 정하는 것이다. 일반적으로 트랜잭션은 메서드에 들어가면서 트랜잭션 시작, 그 메서드를 빠져나오면서 트랜잭션 커밋처럼 결정한다. 트랜잭션 대상이 되는 메서드에서 호출된 메서드는 모두 트랜잭션의 대상이 된다.

 

그러므로 트랜잭션 대상의 메서드가 모든 층에 흩어져 있으면 관리하기가 어렵다. 

 

따라서 관리하기 쉽게 일정한 규칙으로 트랜잭션의 시작과 종료가 이루어지는 메서드를 정해야 한다. 이러한 규칙으로 만들어진 트랜잭션의 시작과 종료는 논리적으로 레이어상의 선으로 나타나는데, 이것이 트랜잭션의 경계선이다. 

 

트랜잭션의 경계선은 프레젠테이션 층과 비즈니스 로직 층 사이에 그어지는 것이 일반적이다. 더 구체적으로 말하자면, 프레젠테이션 층에 공개된 비즈니스 로직 층의 서비스 클래스의 메서드가 트랜잭션의 시작이고 끝이다. 즉, 프레젠테이션 층의 클래스에서 서비스 클래스의 메서드를 호출하면 트랜잭션이 시작되고, 서비스 클래스의 메서드가 종료되고 프레젠테이션 층의 클래스로 되돌아갈 때 트랜잭션이 종료된다.

중요한 것은 트랜잭션의 경계를 만들기 위한 트랜잭션 구현을 어떻게 설계할 것인지이다.

 

 

트랜잭션의 시작과 커밋, 롤백과 같은 RDB에 대한 트랜잭션 관리를 소스 코드로 명시하는 것을 명시적 트랜잭션이라고 하고, 소스 코드로 기술하지 않고 정의 파일 등으로 선언해 프레임워크 등에서 제공하는 트랜잭션 처리에 트랜잭션 관리를 시키는 것을 선언적 트랜잭션이라고 한다.

 

 

선언적 트랜잭션

선언적 트랜잭션을 이용하면 비즈니스 로직 층에 포함되는 컴포넌트를 자유롭게 조합할 수 있고, 또한 개발자도 트랜잭션을 의식하지 않고 로직에 전념할 수 있다. 애플리케이션 아키텍처를 유연하게 하려면 선언적 애플리케이션 아키텍처를 적극적으로 선택하는 것이 좋다.

선언적 트랜잭션을 이용할 때, 트랜잭션의 경계가 되는 것은 서비스 클래스의 메서드이다. 서비스 클래스의 메서드가 호출되면 트랜잭션이 시작되고 메서드가 종료되면 트랜잭션이 커밋된다.

명시적 트랜잭션

만약 어떤 사정때문에 명시적 트랜잭션을 구현해야 한다면 프레젠테이션 층의 컨트롤러로 트랜잭션을 구현하고 비즈니스 층에 포함되는 컴포넌트는 트랜잭션으로부터 자유롭게 해야한다.

그렇게 해야 트랜잭션 중첩에 신경 쓰지 않고 비즈니스 로직 층에 있는 컴포넌트를 자유롭게 조합할 수 있기 때문이다.

또한, 프레젠테이션 층에서 트랜잭션을 구현할 때는 트랜잭션 관리가 한 곳에 이루어지게 해야 한다. 예를 들어 컨트롤러 클래스에서 서비스 클래스의 메서드를 호출하기 전후에 트랜잭션의 시작과 종료를 설정하는 것이 좋다.

가장 나쁜 패턴은 비즈니스 로직 층에 포함되는 여러 클래스가 java.sql.Connection을 다루고 트랜잭션을 관리하는 것이다. 컴포넌트 조합 등 이전에 테스트를 포함한 개발 기간이 어느 정도 걸릴지 클로즈 처리나 예외 처리의 복잡함을 고려해보면 무섭기만 하다.

LIST