Transactional 어노테이션의 역할
Transactional 어노테이션은 데이터베이스 트랜잭션을 관리하는 데 사용됩니다.
트랜잭션은 여러 개의 데이터베이스 작업을 원자적인 단위로 묶어주는 기능을 제공하여 데이터 일관성과 안전성을 보장합니다. Transactional 어노테이션을 사용하면 트랜잭션의 시작, 종료, 롤백 등을 자동으로 처리할 수 있습니다.
트랜잭션 경계 설정
: Transactional 어노테이션이 적용된 메서드나 클래스의 실행을 트랜잭션으로 감싸기 때문에
해당 메서드나 클래스의 실행이 트랜잭션의 시작과 종료를 정의합니다.
이는 데이터베이스 작업이 완전하게 실행되거나 아예 실행되지 않도록 보장합니다.
롤백 처리
: 메서드 실행 중 예외가 발생하면 자동으로 롤백되어 이전 상태로 복원됩니다.
이는 데이터베이스 작업 중에 오류가 발생했을 때 데이터의 무결성을 보존하기 위해 중요한 역할을 합니다.
▼ 적용 방법
- 메서드 레벨 적용 : '@Transactional' 어노테이션을 메서드에 직접 적용하여 해당 메서드의 실행을 트랜잭션으로 관리합니다.
- 클래스 레벨 적용 : 클래스 전체에 '@Transactional' 어노테이션을 적용하여 클래스 내 모든 메서드에 대해 트랜잭션을 설정할 수 있습니다.
- 트랜잭션 매니저 설정 : Transactional 어노테이션을 사용하기 위해서는 적절한 트랜잭션 매니저가 설정되어 있어야 합니다.
▼ 주의 사항
- 트랜잭션 범위 : 트랜잭션의 범위를 과도하게 확장하면 성능 문제가 발생할 수 있습니다.
- 중첩 트랜잭션 : 중첩된 트랜잭션은 부가적인 오버헤드를 초래할 수 있으므로 주의해야 합니다.
▼ 속성 설정
▶ Isolation 레벨
트랜잭션 격리 수준을 지정합니다.
격리 수준은 여러 트랜잭션이 동시에 실행될 때 발생할 수 있는 문제를 제어하는 데 사용됩니다.
1. DEFAULT : 기본 격리 수준을 사용. 데이터베이스의 기본 격리 수준이 적용.
2. READ_UNCOMMITTED : 커밋되지 않은 다른 트랜잭션의 변경 사항을 읽을 수 있다.
3. READ_COMMITTED : 다른 트랜잭션이 커밋한 변경 사항만 읽을 수 있다.
4. REPEATABLE_READ : 같은 쿼리를 반복 실행해도 결과가 일관성 있게 유지.
5. SERIALIZABLE : 동시에 여러 트랜잭션이 실행되지 않도록 모든 트랜잭션을 순차적으로 실행.
[ 예시 ]
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUserEmail(Long userId, String newEmail) {
// 메서드 내용
}
▶ Propagation 설정
메서드가 이미 실행 중인 트랜잭션을 참여할지, 새로운 트랜잭션을 시작할지를 결정합니다.
1. REQUIRED : 현재 실행 중인 트랜잭션이 있는 경우 해당 트랜잭션에 참여하고, 그렇지 않은 경우 새로운 트랜잭션을 시작합니다.
2. REQUIRES_NEW : 항상 새로운 트랜잭션을 시작합니다.
3. MANDATORY : 현재 실행 중인 트랜잭션이 없는 경우 예외가 발생합니다.
4. NESTED : 현재 실행 중인 트랜잭션 내에서 중첩된 트랜잭션을 시작합니다.
외부 트랜잭션이 롤백되면 내부 트랜잭션도 롤백됩니다.
5. SUPPORTS : 현재 실행 중인 트랜잭션이 있는 경우 해당 트랜잭션에 참여하고,
그렇지 않은 경우 트랜잭션 없이 실행합니다.
6. NOT_SUPPORTED : 현재 실행 중인 트랜잭션이 있는 경우 해당 트랜잭션을 일시 중지시키고,
메서드를 트랜잭션 없이 실행합니다.
[ 예시 ]
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUserEmail(Long userId, String newEmail) {
// 메서드 내용
}
▶ 롤백 규칙
어떤 종류의 예외가 발생했을 때 롤백이 수행될지를 설정합니다. 롤백할 예외의 클래스를 명시할 수 있습니다.
@Transactional(rollbackFor = {SQLException.class, MyCustomException.class})
public void updateUserEmail(Long userId, String newEmail) throws MyCustomException {
// 메서드 내용
}
≫ 실제 예시
- Spring Framework : Spring에서 Transactional 어노테이션은 데이터베이스 트랜잭션을 관리하기 위해 널리 사용됩니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(String username, String email) {
User user = new User(username, email);
userRepository.save(user);
}
@Transactional(rollbackFor = Exception.class)
public void updateUserEmail(Long userId, String newEmail) throws Exception {
User user = userRepository.findById(userId).orElseThrow(() -> new Exception("User not found"));
user.setEmail(newEmail);
// Some business logic here
if (!isValidEmail(newEmail)) {
throw new Exception("Invalid email format");
}
userRepository.save(user);
}
private boolean isValidEmail(String email) {
// Validation logic here
return email.contains("@");
}
}
위 코드에서는 UserService 클래스 내에 두 개의 메서드가 있습니다.
1. createUser
: 새로운 사용자를 생성하는 메서드입니다. '@Transactional' 어노테이션이 적용되어 있어,
이 메서드가 실행될 때 트랜잭션을 시작하고, 메서드 실행이 완료되면 트랜잭션을 커밋합니다.
따라서 'createUser' 메서드 내의 모든 작업은 하나의 트랜잭션 내에서 실행됩니다.
2. updateUserEmail
: 사용자의 이메일 주소를 업데이트하는 메서드.
'@Transactional(rollbackFor = Exception.class)' 어노테이션이 적용되어 있어, 예외가 발생할 경우에만 롤백됩니다.
이 메서드에서는 사용자를 조회하고 이메일을 업데이트하는 작업을 수행하며, 중간에 예외가 발생하면 롤백됩니다.
≫ 이런 식으로 속성을 설정하여 Transactional 어노테이션을 더욱 세밀하게 제어할 수 있습니다.
'BE > Spring' 카테고리의 다른 글
[Spring] Spring MVC 구조 간단하게 이해하기 (0) | 2020.06.30 |
---|
댓글