프록시(Proxy) 객체와 트랜잭션(Transaction)에 대한 이해

JINNI·2024년 6월 1일
0

[TIL] Java+Spring

목록 보기
13/15
post-thumbnail

프록시(Proxy) 객체

실제 Entity의 정보를 갖고 있는 가짜 Entity 객체. 지연 로딩을 사용해 Entity의 연관 관계로 조회하는 경우 프록시 객체를 활용한다.

🍕프록시 객체의 초기화

: 연관된 Entity를 조회할 때, 실제 데이터를 조회해오는 것이 아니라 Entity에 대한 참조만 갖고 있는 Proxy 객체를 만듦. 그리고 실제 조회를 할 때 DB에서 조회함.
1. 프록시 객체에 실제 데이터 사용
2. 프록시 객체는 실제 Entity가 생성되어 있지 않은 경우, 영속성 컨텍스트에 실제 Entity 생성을 요청함(프록시 객체의 초기화) : org.hibernate.LazyInitializationException
3. 영속성 컨텍스트는 DB를 조회해 실제 Entity 객체를 생성
4. 프록시 객체는 생성된 실제 Entity 객체의 참조를 멤버 변수에 보관
5. 프록시 객체는 실제 Entity 객체를 이용해 결과를 반환



트랜잭션(Transaction)

데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위(더이상 분할이 불가능한 명령들의 모음)

🍕트랜잭션의 특징

  • 하나 이상의 데이터베이스 연산을 포함
  • 해당 연산들은 모두 성공적으로 완료되거나 모두 실패해 아무 일도 안 일어나는 2가지 상황만 가능함.
    e.g. 은행 계좌에서 돈을 인출하는 과정에서 중간에 실패하는 경우 인출되지도, 상대에게 입금되지도 않은 상태가 있을 수 없음.
  • Transaction을 잘 처리하기 위한 4가지 속성(ACID)이 있음.

✅A : Atomicity(원자성)

  • 트랜잭션의 각 문(데이터 읽기, 쓰기, 업데이트, 삭제)은 단일 단위로 처리
  • 전체 명령문이 올바르게 실행 or 아무것도 실행되지 않아야 함
  • 데이터 손실 및 손상이 발생하는 것을 방지
  • 트랜잭션의 모든 작업이 성공적으로 완료되면 Commit, 이외에는 Roll-back되어 모든 변경사항이 취소됨!

✅C : consistency(일관성)

  • 트랜잭션이 미리 정의되고 예측 가능한 방식으로만 테이블을 변경하도록 보장
  • 트랜잭션이 실행되기 전과 후에 데이터베이스가 일관된 상태를 유지
  • 데이터 손상이나 오류로 인해 테이블 무결성에 의도하지 않은 결과가 발생하지 않도록 보장(항상 데이터베이스 무결성 제약 조건이 만족되어야 함)
    데이터베이스 무결성 제약 조건 : 데이터베이스 테이블에 신뢰할 수 없는 데이터 입력을 못하도록 하는 제약 조건(실세계적인 관점에서는 업무 규칙을 말함)

✅I : Isolation(고립성)

  • 여러 사용자가 동일한 테이블에서 동시에 읽고 쓰는 경우 트랜잭션을 격리하면 동시 트랜잭션이 서로 방해하거나 영향을 미치지 않도록 보장(다른 트랜잭션의 연산에 끼어들 수 없음)
  • 동시에 발생하더라도 하나씩 발생하는 것처럼 발생할 수 있음(시스템에 혼자 실행되는 것처럼 작동)
  • 하나의 특정 트랜잭션이 완료될 때까지 다른 트랜잭션의 특정 트랜잭션의 결과를 참조할 수 없음

✅D : Durability(영속성)

  • 트랜잭션이 성공적으로 커밋되면 그 결과가 영구적으로 저장되어 시스템 장애가 발생해도 유지되어야 함
  • 성공적으로 실행된 트랜잭션으로 인해 변경된 데이터가 시스템 오류가 발생하는 경우에도 저장
  • 데이터베이스가 안정적인 저장소에 데이터를 기록해 달성

🍕@Transactional 어노테이션

  • 트랜잭션은 기본적으로 아래와 같이 동작.
// Entity Manager 의존성 주입
private final EntityManager em;

// Transaction 의존성 주입
private final EntityTransaction transaction = em.getTransaction();

...
void businessLogic() {
 transaction.begin(); // 트랜잭션 시작
 logic(em);
 transaction.commit(); // 트랜잭션 커밋
}
  • 하지만 매번 '트랜잭션을 시작 → 비즈니스 로직 → 트랜잭션 커밋'을 반복하는 것은 비효율적이고 불편함
  • Spring엔 트랜잭션을 지원하기 위한 @Transactional 어노테이션(org.springframework.transaction.annotation.Transactional;)이 존재함!
  • Service 계층에서 @Transactional 어노테이션을 선언적으로 사용
  • AOP(Aspect Oriented Programming)을 이용해 @Transactional을 구현, Proxy 객체를 활용함.
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {

    private final MemberJpaRepository memberJpaRepository;

    public MemberGetResponse getMemberByIdV1(Long id) {
        Member member = memberJpaRepository.findById(id).get();
        return MemberGetResponse.of(member);
    }
 
    @Transactional
    public String create(MemberCreateRequest request) {
         Member member =  memberJpaRepository.save(Member.builder()
                 .name(request.getName())
                 .nickname(request.getNickname())
                 .age(request.getAge())
                 .sopt(request.getSopt())
                 .build());
         return member.getId().toString();
    } 
}
  1. @Transactional의 대표적인 속성 : readOnly
  • readOnly = true로 하는 경우, 트랜잭션 커밋 시 영속성 컨텍스트가 flush하지 않음.
  • 기존 Entity와 스냅샷을 비교해 DB에 반영하는 로직이 없기 때문에 성능이 향상
    only 조회를 할 때에는 readOnly = true를 하는 것이 좋음
  1. @Transactional은 Proxy 객체를 이용하기 때문에 private method 위에 선언 시 동작 X


참고자료
33기 DO SOPT 서버 파트 3차 세미나 자료(배포 불가)
What are ACID Transactions?
[MYSQL] 📚 트랜잭션(Transaction) 개념 & 사용 💯 완벽 정리
정보통신기술용어해설 Integrity Constraint 무결성 제약조건

profile
천재 개발자 되기

0개의 댓글