Spring/Spring Data JPA

[Spring Data JPA] 2-2. Transactionality

noahkim_ 2023. 10. 18. 02:25

1. 기본 트랜잭션 설정

CrudRepository 메서드
  • SimpleJpaRepository로부터 트랜잭션 설정을 상속받습니다.
    • 읽기 작업의 경우, 트랜잭션 설정의 readOnly 플래그는 true로 설정됩니다.
    • 그 외의 모든 작업은 @Transactional로 설정됩니다. (기본 트랜잭션 설정이 적용되도록)

 

2. 트랜잭션 설정 커스터마이징

특정 저장소 메서드의 트랜잭션 설정 조정
  • Method Override (+@Transactional 설정)
  • findAll() 메서드는 10초의 타임아웃을 갖고 readOnly 플래그 없이 실행됩니다.
public interface UserRepository extends CrudRepository<User, Long> {

  @Override
  @Transactional(timeout = 10)
  public List<User> findAll();

  // Further query method declarations
}

 

3. 트랜잭션 행동 변경

파사드 구현

  • 트랜잭션 경계를 정의하기 위해 서비스 또는 파사드 구현 방법이 있습니다. (여러 저장소 사용 고려)

 

파사드 활성화
  • <tx:annotation-driven /> 활성화
  • @EnableTransactionManagement
@Configuration
@EnableTransactionManagement
public class AppConfig {

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }
}

 

 

외부 트랜잭션 설정
@Service
public class UserManagementImpl implements UserManagement {

    private final UserRepository userRepository;
    private final RoleRepository roleRepository;

    public UserManagementImpl(UserRepository userRepository, RoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
    }

    @Transactional
    public void addRoleToAllUsers(String roleName) {
	 Role role = roleRepository.findByName(roleName);

    	for (User user : userRepository.findAll()) {
            user.addRole(role);
            userRepository.save(user);
        }
    }
}
  • addRoleToAllUsers(...): 해당 트랜잭션 경계 안에서 메서드들이 하나의 트랜잭션으로 실행됨
  • 실제로 사용될 트랜잭션이 설정됩니다.  (저장소에서의 트랜잭션 설정은 무시)

 

JPA와의 일관성

  • 영속성 컨텍스트를 통해 엔터티의 상태 변화를 자동으로 추적

 

dirty check
  • 엔터티는 자동으로 변경사항이 감지됨
  • 트랜잭션이 커밋될 때 자동으로 엔티티의 변경 상태를 데이터베이스에 반영함
  • save 호출 필요 X (일관성을 위해 save()를 호출하는 것이 좋음)

 

4. Transactional query methods

트랜잭션 기본 설정

  • 선언된 쿼리 메서드는 트랜잭션 설정 X
  • 이러한 메서드들을 트랜잭셔널하게 실행하려면, 정의한 저장소 인터페이스에 @Transactional 어노테이션 사용하세요.

 

readOnly 플래그

읽기 전용 쿼리에 대한 트랜잭션
  • JDBC 드라이버에 힌트로 전달 (성능 최적화용)
  • 조작 쿼리가 발생하지 않도록 하는 검사 X

 

최적화 수행 (기본 JPA 제공자에 한함)
  • flushMode=NEVER
  • 성능 향상 (큰 객체 트리에서)

 

@Transactional(readOnly = true)
interface UserRepository extends JpaRepository<User, Long> {

  List<User> findByLastname(String lastname);

  @Modifying
  @Transactional
  @Query("delete from User u where u.active = false")
  void deleteInactiveUsers();
}

 

  • 대부분의 쿼리 메서드가 데이터를 읽기만 하도록 @Transactional(readOnly = true) 어노테이션을 사용하였습니다.
  • deleteInactiveUsers() 메서드는 데이터를 수정하는 메서드입니다.
    • @Modifying 어노테이션 사용
    • 트랜잭션 설정을 재정의하여 readOnly 플래그를 false로 설정

 

 

 

출처