Spring Data JPA는
Repository를 통해 save하거나 find하는데,
이 과정중에 트랜잭션 처리를 어떻게 하는지는
겉으로 보이지 않았다
그래서,
Spring에서 트랜잭션을 관리하는 것에 대해
자세히 알고자 한다.
바닐라 JPA를 사용했을 때
EntityFactory로 부터 EntityManager를 생성하고,
생성한 manager에서 EntityTransaction을 가져와
data를 save하거나 find했었다.
이 방식처럼 Spring Boot를 사용하지 않는다면,
@Configuration
@EnableTransactionManagement
public class JpaConfig{
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
...
return em;
}
...
@Bean
public PlatformTransactionManager transactionManager(){
JpaTransactionManager tx = new JpaTransactionManager();
tx.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return tx;
}
}
Configuration을 통해
EntityManagerFactory
와 TransactionManager
를
Bean으로 등록하여 사용한다.
SpringBoot를 사용하고 있다면, 위와 같은 트랜잭션 설정을
내부적으로 알아서 해주기 때문에
@Service
@Transactional
public classs EntityService{
...
public Entity createEntity(Entity entity){
return repository.save(entity);
}
...
}
트랜잭션이 필요한 클래스에 (보통은 service)
@Transactional
annotation을 사용하여 적용한다.
참 간단하다
EntityManager
와 EntityTransaction
으로
try/catch를 사용해서 rollback시키는 방법과 비교했을 때
단 한줄만으로 트랜잭션 관리가 이루어지는 것이다.
@Service
@Transactional
public classs EntityService{
...
@Transactional(readOnly=True)
public Entity findEntity(long id){
return repository.findById(id);
}
...
}
각 메서드 별로 @Transactional
annotation을 설정해
위와 같이 readOnly 같이 세부 설정도 가능한거 같다.
만약 별도의 설정값 없이
@Transactional
annotation이 있는 메서드에서
@Transactiona
인 다른 메서드를 사용하는 상황이 있을 때
호출하는 메서드에서 오류가 생겨 rollBack 시
호출 당하는 메서드도 rollBack 된다.
이렇게 여러 트랜잭션을 묶어
하나의 트랜잭션 경계로 만들 수 있는데,
트랜잭션 경계에서 다음 트랜잭션을
어떻게 진행할지 결정하는 것이 propagation이다.
default값으로
진행중인 트랜잭션이 없으면 새로 시작하고,
있다면 해당 트랜잭션에 참여한다.
진행중인 트랜잭션과 무관하게
트랜잭션이 새로 시작되며
기존 트랜잭션은 새로 시작된 트랜잭션이 종료할 때 까지
중지하게 된다.
진행중인 트랜잭션이 없으면 예외를 발생
트랜잭션이 필요하지 않음을 뜻하고
만약 진행중인 트랜잭션이 있으면NOT_SUPPORTED
로 설정한 메서드가 종료될 때 까지 중지된다.
트랜잭션이 필요하지 않고,
만약 진행중인 트랜잭션이 있으면 예외를 발생
트랜잭션의 ACID원칙 중 I원칙에 따라
각 트랜잭션은 서로 독립적으로 실행되는데,
@Transactional
에서 isolation을 통해
트랜잭션간 간섭 정도를 변경할 수 있다.
다른 트랜잭션에서 아직 commit하지 않은 데이터를 읽을 수 있음
다른 트랜잭션에서 commit한 데이터를 읽을 수 있음
트랜잭션 내에서 한 번 조회한 데이터를 반복해서 조회해도 같은 데이터가 조회되도록 한다.
동일한 데이터에 대해 동시에 두 개 이상의 트랜잭션에서 관리하지 못하도록 한다.
이러한 isolation 설정값이 존재하기는 하나,
보통은 DB에 설정된 level을 따르는 것이 권장된다고 하여
DEFAULT
값을 사용한다고 한다.