
트랜잭션은 데이터베이스에서 작업을 하느의 단위로 묶어 처리하는 개념으로 여러 작업을 하나의 트랜잭션으로 묶으면 모든 작업이 성공적으로 완료되거나 모두 실패해야합니다. 트랜잭션은 데이터의 일관성과 무결성을 유지하는데 중요한 역할을 하며, 데이터베이스가 신뢰할 수 있는 상태를 유지하는데 필수적입니다.
트랜잭션은 ACID 속성을 만족해야 데이터 무결성을 보장할 수 있습니다.
트랜잭션 내의 모든 작업이 전부 완료되거나 전부 실패해야 한다는 성질입니다. 부분적으로 성공한 작업은 허용되지 않으며 중간에 오류가 발생하면 트랜잭션 전체가 롤백됩니다.
트랜잭션이 완료되면 데이터베이스가 일관된 상태를 유지해야합니다. 트랜잭션 전후로 데이터베이스 상태는 제약 조건을 충족해야합니다.
여러 트랜잭션이 동시에 실행되더라도 각 트랜잭션은 서로 간섭하지 않고 독립적으로 실행되어야합니다. 이를 통해 트랜잭션 간 데이터 충돌을 방지 할 수 있습니다.
트랜잭션이 성공적으로 완료되면 그 결과는 데이터베이스에 저장됩니다. 시스템 오류가 발생하더라도 커밋된 데이터는 보존됩니다.
트랜잭션은 다음과 같은 단계를 거쳐 실행됩니다.
트랜잭션 격리 수준은 여러 트랜잭션이 동시에 실행될 때 트랜잭션 간에 어느 정도 영향을 주고 받을 지 결정하는 설정입니다. 격리 수준이 높을 수록 데이터 일관성은 보장되지만 성능이 저하될 수 있습니다.
가장 낮은 격리 수준으로 트랜잭션이 커밋도지 않은 데이터를 다른 트랜잭션에서 읽을 수 있는 상태입니다. 이로 인해 발생하는 문제를 더티 리드라고 하며 이는 트랜잭션 간에 데이터의 불일치 문제를 일으킬 수 있습니다.
특징 :
트랜잭션이 커밋된 데이터만 읽을 수 있도록 허용하는 격리 수준입니다. 즉 한 트랜잭션이 데이터를 수정하고 커밋하지 않은 상태에서는 다른 트랜잭션이 그 데이터를 읽을 수 없습니다. 더티 리드는 방지 할 수 있지만 반복 불가능한 읽기 문제는 발생할 수 있습니다.
특징 :
트랜잭션 내에서 동일한 데이터를 여러번 읽어도 항상 같은 결과를 보장하는 격리 수준입니다. 즉, 트랜잭션이 시작된 시점의 데이터를 기준으로 읽기를 수행하며 다른 트랙잭션이 해당 데이터를 수정할 수 없습니다. 반복 불가능한 읽기 문제는 해결되지만 여전히 팬텀 리드 문제가 발생할 수 있습니다.
가장 높은 수준의 격리로 트랜잭션들이 완전히 직렬화된 것처럼 동작하도록 보장합니다. 즉,트랜잭션이 서로 완전히 격리되어 다른 트랜잭션이 동일한 데이터를 동시에 접근할 수 없습니다. 이 격리 수준에서는 더티리드,반복불가능한 읽기, 팬텀 리드 모두 방지 됩니다.

Spring은 @Transactional 어노테이션을 통해 트랜잭션을 간단하게 관리할 수 있습니다. 이 어노테이션을 붙이면 해당 메서드나 클래스 내의 모든 데이터 베이스 작업이 하나의 트랜잭션으로 처리됩니다.
@Transactional
public TodoSaveResponse saveTodo(AuthUser authUser, TodoSaveRequest todoSaveRequest) {
User user = User.fromAuthUser(authUser);
String weather = weatherClient.getTodayWeather();
Todo newTodo = new Todo(
todoSaveRequest.getTitle(),
todoSaveRequest.getContents(),
weather,
user
);
Todo savedTodo = todoRepository.save(newTodo);
return new TodoSaveResponse(
savedTodo.getId(),
savedTodo.getTitle(),
savedTodo.getContents(),
weather,
new UserResponse(user.getId(), user.getEmail(), user.getNickName())
);
}
트랜잭션은 데이터베이스의 일관성과 무결성을 보장하기 위한 중요한 개념입니다. ACID 속성을 통해 트랜잭션이 안전하게 수행되며 , Spring 에서는 @Transactional을 통해 손쉽게 트랜잭션을 관리할 수 있습니다.
@Transactional을 선언하면 해당 클래스의 모든 메서드에 적용되며 ,메서드에 별도로 @Transactional을 선언하면 해당 메서드가 우선 적용됩니다.