트랜잭션이란?

토닉·2022년 10월 5일
0

스프링 프레임워크를 사용하면서 @Transactional 이라는 어노테이션을 많이 사용했습니다. 트랜잭션이라는 대략적인 개념만 알고 알아서 잘 동작하겠지 라는 마음으로 사용하다가 DB에 데이터를 넣는 과정에서 동시성 문제가 발생했고 이를 해결하면서 트랜잭션이 데이터베이스에서 어떻게 동작하고 @Transactional 은 어떤 기능을 제공해주는지 학습하게 되었습니다. 이 글은 MySQL 환경을 예시로 작성되었습니다.

트랜잭션

하나의 논리적인 작업 단위라고 불립니다. 다른 얘기로 눈리적인 이유로 여러 SQL문들을 단일 작업으로 묶어서 나눠질 수 없게 만든 것이 트랜잭션 입니다. 따라서 트랜잭션 내에서 sql 문은 모두 반영되거나 반영되지 않아야 합니다.

start transaction;
update member set name='after' where name='before';
commit;

위 쿼리문을 실행하면 member 테이블에 before 라는 이름을 가진 로우는 after 로 바뀌고 DB에 반영이 됩니.

start transaction;
update member set name='after' where name='before';
rollback;

반면에 롤백을 하게되면 반영이 되지 않습니다.

그렇다면, MySQL에서는 매번 쿼리문을 반영시키기 위해 위 과정을 반복해야할까요?

autocommit 이란 각각의 SQL문을 자동으로 transaction 처리 해주는 개념입니다. SQL문이 성공적으로 실행되면 자동으로 커밋하고 문제가 발생하면 알아서 롤백합니다. MySQL에서는 default로 autocommit이 enable 되어 있습니다. 다른 DBMS에서도 대부분 같은 기능을 제공하게 됩니다. 위에서 1이라는 뜻은 autocommit 켜져있다는 뜻입니다.

set autocommit=0;
insert into member values (501, 'a', 'b', 'c', 'd');
select * from member where member_id=501; // find member
rollback;
select * from member where member_id=501; // Empty set (0.01 sec)

autocommit 을 끄고 쿼리문을 실행하면 쿼리가 커밋되지 않았기 때문에 롤백을 하면 취소됩니다 autocommit 이 켜져있는 상태에서 start transaction; 을 실행하게 되면 autocommit은 꺼지고 commit, rollback 을 통해 transaction 을 종료하면 원래 autocommit 상태로 돌아가게 됩니다.

Java에서 트랜잭션 사용하기

public void query(String sql) {
	try (Connection connection){
		connection.setAutoCommit(false); // 설정하지 않으면 true이다.
		...// 비즈니스 로직
		connection.commit(); // 비즈니스 로직에 에러가 발생하지 않으면 Commit
	} catch (SQLException e){
		connection.rollback(); // 에러가 발생하면 rollback
	} finally {
		connection.setAutoCommit(true);
	}
}

Connection 클래스를 통해 연결하고자 하는 데이터베이스와 연결할 수 있습니다. 이 커넥션은 별다른 설정을 하지 않으면 default로 autocommit이기 때문에 커넥션에서 실행한 모든 쿼리문은 독립적으로 커밋하게 됩니다. 별도의 논리적 단위로 트랜잭션을 묶고 싶다면 위 코드처럼 작성해주면 개발자가 트랜잭션의 범위를 정할 수 있습니다.

Spring에서 트랜잭션 사용하기

@Transactional
public void query(String sql) {
		...// 비즈니스 로직
}

Spring의 @Transactional 을 사용하면 Java에서 트랜잭션을 하기 위한 중복 로직들을 걷어내고 오로지 비즈니스 로직만 집중해서 사용할 수 있습니다.

ACID

트랜잭션하면 빼놓을 수 없는 개념입니다. 트랜잭션이 어떤 속성을 지녀야 하는지에 대한 4가지 속성입니다.

Atomicity

트랜잭션 내의 쿼리는 모두 성공하거나 모두 실패해야 합니다. 트랜잭션은 논리적으로 쪼개질 수 없는 작업 단위이기 때문입니다. 중간에 SQL문이 실패하면 지금까지의 모든 작업을 취소해서 아무 일도 없었던 것처럼 롤백을 해주어야 합니다. 이 속성에서 개발자은 언제 커밋할지 롤백해야 할지를 정해주면 됩니다. 나머지 DB에 영구적으로 저장하는 것과 이전 상태로 되돌리는 것은 DBMS가 담당하게 됩니다.

Consistency

데이터베이스의 일관성을 지켜주어야 합니다. 트랜잭션이 DB에 정의된 rule을 위반했는지 DBMS가 커밋하기 전에 확인하고 알려주어야 합니다. DB에 정의된 role외에 애플리케이션 관점에서 트랜잭션이 consistent하게 동작하는지는 개발자가 챙겨주어야 합니다.

Isolation

서로 다른 트랜잭션은 서로에게 영향을 주면 안됩니다. 다른 얘기로 여러 트랜잭션이 동시에 실행될 때도 혼자 실행되는 것처럼 동작하게 만듭니다. 하지만, 이 속성은 동시성을 컨트롤할 때 성능 저하의 문제가 될 수 있습니다. 따라서 DBMS의 종류에 따라 여러 종류의 isolation level을 제공합니다. 개발자는 isolation level 중에 어떤 level로 트랜잭션을 동작시킬지 설정할 수 있습니다.

Durability

커밋된 트랜잭션은 DB에 영구적으로 저장해야 합니다. DB System에 문제가 발생하더라도 커밋된 트랜잭션은 DB에 남아있어야 하는 속성입니다. 영구적으로 저장한다는 뜻은 비휘발성 메모리(hdd, ssd …)에 저장함을 의미합니. 이 속성은 기본적으로 DBMS에서 보장하도록 되어있습니다.

정리

트랜잭션의 속성은 DBMS가 모든 것을 알아서 해주는 것이 아닌 개발자가 챙겨야 하는 부분이 있기 때문에 트랜잭션의 개념과 ACID 속성을 잘 숙지해주어야 합니다.

참고 자료

쉬운 코드

profile
우아한테크코스 4기 교육생

0개의 댓글