트랜잭션
트랜잭션 과정에서는 어떠한 동작이 완료되기 전까지 방해가 존재해서는 안된다.
예를 들어서 송금을 하는 일련의 트랜잭션이 있다고 하자. 그 과정은 송금자의 계좌에서 돈이 감소하고, 수신인의 계좌에선 돈이 증가해야한다. 만일 송금자의 계좌의 돈만 감소하고 수신인의 돈은 증가하지 않는 상황은 발생해서는 안된다는 것이다.
@Transactional
스프링에서는 @Transactional 어노테이션을 지원한다. 이를 클래스 단위에 붙이면(클래스 선언위에 어노테이션을 사용하면) 해당 클래스의 메소드 모두 트랜잭션을 보장한다. 메소드 개별적으로도 사용이 가능한데 @Transactional에는 readOnly 설정을 할 수 있는데, 만일 어떠한 엔티티의 조회와 같이 데이터의 변경이 필요하지 않은 메소드에 readOnly = true를 해주면, 좀 더 성능이 최적화된다. 근데 만일 데이터 변경하는 메소드에 readOnly = true 하면 데이터 변경이 안되어서 망하니 주의하자.
1) 메소드 전체에 트랜잭션 적용
package jpabook.jpashop.service;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.Null;
import java.util.List;
@Service
//트랜잭션 상황에서는 꼭 @Transactional 어노테이션 필요
//클래스 범위에서 @Transactional 어노테이션이 있으면 메서드들도 모두 트랜잭션 안에서 작동
@Transactional
public class MemberService {
@Autowired
private MemberRepository memberRepository;
/**
* 회원 가입
*/
public Long join(Member member) {
validateDuplicateMember(member); // 중복 회원 가입 방지
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
List<Member> findMembers = memberRepository.findByName(member.getName());
if (!findMembers.isEmpty()) {
throw new IllegalStateException("이미 존재하는 회원입니다");
}
}
//회원 전체 조회
public List<Member> findMembers() {
return memberRepository.findAll()
}
//회원 단건 조회
public Member findOne(Long memberId) {
return memberRepository.find(memberId);
}
}
2) 필요한 메소드에 readOnly 설정 (좀더 성능 최적화)
package jpabook.jpashop.service;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.Null;
import java.util.List;
@Service
//트랜잭션 상황에서는 꼭 @Transactional 어노테이션 필요
//클래스 범위에서 @Transactional 어노테이션이 있으면 메서드들도 모두 트랜잭션 안에서 작동
@Transactional
public class MemberService {
@Autowired
private MemberRepository memberRepository;
/**
* 회원 가입
*/
public Long join(Member member) {
validateDuplicateMember(member); // 중복 회원 가입 방지
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
List<Member> findMembers = memberRepository.findByName(member.getName());
if (!findMembers.isEmpty()) {
throw new IllegalStateException("이미 존재하는 회원입니다");
}
}
//회원 전체 조회
@Transactional(readOnly = true)
// 조회 같이 데이터 변경이 되지 않는곳에서 readOnly = true를 하면 성능이 좀더 좋음.
// 만일 데이터 변경이 되는 곳에서 readOnly = true하면 데이터 변경이 안되서 망함.
public List<Member> findMembers() {
return memberRepository.findAll()
}
//회원 단건 조회
@Transactional(readOnly = true)
public Member findOne(Long memberId) {
return memberRepository.find(memberId);
}
}
클래스단에 @Transactional을 선언해도 메서드 위에 따로 선언한 @Transactional이 우선순위를 가진다.
'Spring > SpringBoot' 카테고리의 다른 글
SpringBoot- @GetMapping, @PostMapping (0) | 2023.06.28 |
---|---|
SpringBoot- Controller (0) | 2023.06.25 |
SpringBoot- 테스트 케이스 작성 예시 (0) | 2023.06.20 |
SpringBoot- EntityManager 생성법 (0) | 2023.06.20 |
SpringBoot- 기본 스프링 부트 설정 (0) | 2023.06.20 |