정의: 하나의 작업 단위(작업의 묶음)로 간주되어, 모두 성공하거나 모두 실패해야 하는 작업을 의미합니다.
특징 (ACID):


Spring에서는 @Transactional 어노테이션을 사용하여 트랜잭션을 선언적으로 관리할 수 있습니다.
@Transactional 사용법
@Service
public class UserService {
@Transactional // 트랜잭션 시작
public void updateUser(Long userId, String newName) {
User user = userRepository.findById(userId).orElseThrow();
user.setName(newName); // 변경
} // 트랜잭션 커밋 또는 롤백
}
@Transactional 어노테이션이 붙은 메서드에서:롤백(Rollback) :
트랜잭션에서 문제가 발생하거나, 작업이 완료되지 않았을 때 이전 상태로 되돌리는 작업을 말합니다.
Spring에서의 롤백 처리:
Spring의@Transactional은 기본적으로 RuntimeException이 발생하면 롤백을 실행합니다.@Transactional public void updateUser(Long userId, String newName) { User user = userRepository.findById(userId).orElseThrow(); user.setName(newName); if (newName.isEmpty()) { throw new RuntimeException("이름은 비어 있을 수 없습니다."); // 롤백 발생 } }
- CheckedException 처리:
CheckedException은 기본적으로 롤백되지 않으므로, 명시적으로 롤백 설정이 필요합니다.@Transactional(rollbackFor = Exception.class) public void updateUserWithCheckedException(Long userId, String newName) throws Exception { User user = userRepository.findById(userId).orElseThrow(); user.setName(newName); throw new Exception("테스트 예외"); // 롤백 발생 }
- 롤백 시 주의사항:
- 롤백은 트랜잭션의 변경 사항만 되돌리며, 외부 시스템(API 호출, 파일 쓰기 등)은 롤백되지 않음.
- 트랜잭션이 포함되지 않은 작업은 롤백 시 영향을 받지 않음.
Spring Data JPA는 JPA의 더티 체킹을 그대로 활용합니다.
더티 체킹 동작 예시
@Transactional
public void updateUserEmail(Long userId, String newEmail) {
User user = userRepository.findById(userId).orElseThrow();
user.setEmail(newEmail); // 엔티티 상태 변경
} // 트랜잭션 종료 시점에 자동으로 UPDATE 쿼리 실행
엔티티를 수동으로 저장(save) 하지 않아도, 변경 사항이 자동으로 반영됩니다.

| 구분 | 설명 | 관련 SQL |
|---|---|---|
| PERSIST(중요) | 새로운 엔티티를 영속성 컨텍스트에 추가 | INSERT |
| MERGE | 준영속/비영속 상태의 엔티티를 영속 상태로 변경 | - |
| REMOVE(중요) | 엔티티를 영속성 컨텍스트와 DB에서 삭제 | DELETE |
| REFRESH | DB의 데이터로 엔티티를 다시 조회하여 갱신 | - |
| DETACH | 영속성 컨텍스트에서 엔티티를 분리(준영속 상태로 전환) | - |
트랜잭션은 서비스 계층에서 관리하는 것이 좋습니다. (DAO 계층에서 사용하지 않음)
트랜잭션 범위가 넓으면 성능에 영향을 미칠 수 있으므로, 최소한으로 유지.
@Transactional은 프록시 방식으로 동작하므로, 동일 클래스 내 메서드 호출 시 트랜잭션이 적용되지 않을 수 있음.
프록시(Proxy) :
JPA에서 지연 로딩(Lazy Loading)을 위해 사용하는 기술로, 실제 엔티티 대신 프록시 객체를 반환하여 필요할 때 데이터를 로드합니다.
- 지연 로딩과 즉시 로딩:
- 지연 로딩(Lazy Loading): 엔티티를 조회할 때 연관 데이터를 바로 로드하지 않고, 실제 접근 시점에 로드.
- 즉시 로딩(Eager Loading): 엔티티를 조회할 때 연관 데이터를 즉시 로드.
- 프록시 객체 동작:
@Entity class User { @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) private List<Order> orders; }User user = entityManager.find(User.class, 1L); // User는 로드되지만 Orders는 로드되지 않음 List<Order> orders = user.getOrders(); // 이 시점에 Orders 쿼리가 실행- 주의사항:
- 프록시 객체를 사용할 때, 영속성 컨텍스트가 닫히면 LazyInitializationException이 발생할 수 있음.
- 지연 로딩을 무조건 사용하는 것이 아니라, 실제 데이터 사용 패턴에 맞게 설정해야 성능 최적화 가능.
변경 감지를 위해 엔티티를 영속성 컨텍스트에서 관리해야 합니다.
영속성 컨텍스트에 너무 많은 엔티티가 있으면 성능이 저하될 수 있음.
불필요한 변경이 발생하지 않도록 엔티티 상태를 신중히 관리.
영속성 컨텍스트 :
JPA에서 하나의 트랜잭션 내에서 조회된 엔티티 객체를 보관하는 공간으로, 데이터베이스와의 연결을 관리하며 엔티티 상태를 추적합니다. 트랜잭션이 종료되면 영속성 컨텍스트도 사라지며, 영속성 컨텍스트는 트랜잭션 당 하나입니다.
이를 통해 더티 체킹과 1차 캐시, 지연 로딩 등의 기능을 제공할 수 있습니다.
- 동작 방식:
- 엔티티 조회 시 1차 캐시 사용:
이미 조회된 엔티티는 영속성 컨텍스트에서 관리되므로, 다시 조회 시 데이터베이스 쿼리를 실행하지 않습니다.User user1 = entityManager.find(User.class, 1L); // DB 조회 User user2 = entityManager.find(User.class, 1L); // 캐시에서 조회- 엔티티 변경 감지:
영속성 컨텍스트는 엔티티 상태를 추적하며, 트랜잭션 종료 시 변경된 데이터를 자동으로 반영합니다.- 장점:
- 1차 캐시로 반복 조회 시 성능 최적화.
- 변경 사항 추적 및 더티 체킹.
- 데이터 일관성 보장.