❓ DB Transaction
- 여러번의 DB Access 작업을 하나의 논리적인 작업 그룹으로 만들고,
그 그룹을 DB에 일괄적으로 전체반영/전체취소 되도록 만들어주는 단위
부분적인 성공/취소를 허용하지 않음
📌 @Transactional
선언적 트랜잭션 처리를 지원하는 어노테이션(보통 Service에 부착)
- 데이터의 일관성을 유지하기 위해 트랜잭션을 처리한다.
✔️ @Transactional 특징
- @Transactional 어노테이션은 인터페이스, 클래스, 메소드에 붙일 수 있다.
- 인터페이스에 지정하면 해당 인터페이스를 구현한 구현객체의 각 메소드가 실행될 때마다 트랜잭션처리가 지원된다.
- 클래스에 지정하면 해당 클래스로 생성한 객체의 각 메소드가 실행될 때마다 트랜잭션처리가 지원된다.
- 메소드에 지정하면 해당 메소드가 실행될 때마다 트랜잭션처리가 지원된다.
- 선언적 트랜잭션 처리가 지원되면 해당 메소드가 실행되기 전에 새로운 트랜잭션이 시작된다.
- 트랜잭션이 시작된다는 말은, 데이터베이스에서 지금부터 실행하는 모든 SQL 구문의 하나의 논리적인 그룹으로 묶을 준비가 되었다는 것이다.
- 메소드 내에서 데이터베이스 액세스 작업을 할 때마다 해당 SQL작업을 트랜잭션에 추가한다.
- 선언적 트랜잭션 처리가 지원되면 해당 메소드가 종료될 때 트랜잭션을 종료한다.
- 해당 메소드를 실행하면서 RuntimeException의 하위 예외가 발생하면 해당 트랜잭션에 추가된 모든 작업에 대해서 rollback을 실행한다.
(* RuntimeException 및 그 하위 예외가 아니라면 Exception의 하위여도 해당 안됨)
- 해당 메소드를 실행하면서 예외가 발생하지 않으면 해당 트랜잭션에 추가된 모든 작업에 대해서 commit을 실행한다.
💡 예시)
- Class 파일에 @Transactional 어노테이션 부착
@Service
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
public void registerUser(User user) {
User savedUser = userDao.getUserById(user.getId());
if (savedUser != null) {
throw new RuntimeException("["+user.getId()+"] 아이디가 이미 사용중입니다.");
}
userDao.insertUser(user);
}
public User getUserDetail(String id) {
User savedUser = userDao.getUserById(id);
if (savedUser == null) {
throw new RuntimeException("["+id+"] 아이디에 해당하는 사용자 정보를 찾을 수 없습니다.");
}
return savedUser;
}
}