본문 바로가기

Spring&IntelliJ

1. 쓰기 지연과 지연 로딩에 대해서, 2.로우(ROW)락과 쓰기지연에 대해서

1. 쓰기 지연과 지연 로딩에 대해서

JPA에서 쓰기지연과 지연로딩은 다른거야?

 

네, 완전히 다른 개념입니다.

쓰기 지연은 INSERT·UPDATE·DELETE SQL 실행을 트랜잭션 커밋 시점까지 미루는 기능이고, 지연 로딩은 연관된 엔티티를 실제로 사용하는 시점까지 SELECT 조회를 미루는 기능이다. 둘 다 "지연"이라는 단어가 들어가지만 전혀 다른 기능이다.

 

이름이 비슷해서 헷갈리기 쉽지만, 적용되는 대상도 다르고 목적도 다릅니다.

구분쓰기 지연(Write-Behind)지연 로딩(Lazy Loading)
대상 INSERT, UPDATE, DELETE SELECT
목적 SQL 실행을 모아서 성능 향상 필요한 시점에만 조회
발생 시점 데이터를 저장/수정할 때 연관 객체를 조회할 때
관련 기능 영속성 컨텍스트, 쓰기 지연 SQL 저장소 프록시(Proxy), 연관관계
핵심 "나중에 DB에 반영" "나중에 DB에서 조회"

1. 쓰기 지연

예를 들어:

 
Member member = new Member();
member.setName("kim");

em.persist(member);
 

이때 많은 사람들이:

persist() 호출
↓
즉시 INSERT SQL 실행
 

이라고 생각하는데,

실제로는:

persist()
↓
영속성 컨텍스트 저장
↓
쓰기 지연 SQL 저장소에 INSERT 저장
↓
commit()
↓
INSERT 실행
 

입니다.

즉 SQL 실행을 미뤄둡니다.


예를 들어:

 
em.persist(member1);
em.persist(member2);
em.persist(member3);

tx.commit();
 

실행 순서:

persist(member1)
persist(member2)
persist(member3)

(아직 INSERT 안 나감)

commit()

INSERT
INSERT
INSERT
 

2. 지연 로딩

예를 들어:

 
@Entity
public class Order {

    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;
}
 

조회:

 
Order order = em.find(Order.class, 1L);
 

실행 SQL:

 
SELECT *
FROM orders
WHERE id = 1
 

여기서는 Member를 안 가져옵니다.


이후:

 
order.getMember().getName();
 

를 호출하는 순간

추가 SQL 발생:

 
SELECT *
FROM member
WHERE id = ?
 

필요할 때까지 조회를 미룸
 

이게 지연 로딩입니다.


기억하는 방법

쓰기 지연

DB에 쓰는 것
(INSERT, UPDATE, DELETE)

나중에 실행
 

지연 로딩

DB에서 읽는 것
(SELECT)

나중에 실행
 

한 문장으로 정리

쓰기 지연은 INSERT·UPDATE·DELETE SQL 실행을 트랜잭션 커밋 시점까지 미루는 기능이고, 지연 로딩은 연관된 엔티티를 실제로 사용하는 시점까지 SELECT 조회를 미루는 기능이다. 둘 다 "지연"이라는 단어가 들어가지만 전혀 다른 기능이다.

 

 

======================================================================================

2.로우(ROW)락과 쓰기지연에 대해서

로우(ROW)락 시간과 쓰기지연은 어떤 관계야? 예를들어 UPDATE, DELETE로 인한 로우락시간 최소화와 쓰기지연은 어떤 관계를 가져?

좋은 질문입니다.

사실 JPA의 쓰기 지연(Write-Behind) 이 존재하는 이유 중 하나가 바로 DB 락(lock) 시간을 최소화하기 위해서입니다.

JPA의 쓰기 지연은 UPDATE·DELETE SQL 실행을 트랜잭션 커밋 직전까지 미루기 때문에, 데이터베이스가 해당 행(ROW)에 락을 거는 시점도 최대한 늦춰진다. 그 결과 Row Lock 유지 시간이 짧아지고 동시성 성능이 좋아지는 효과가 있다. 따라서 쓰기 지연은 단순히 SQL을 모아서 보내는 기능이 아니라 락 경합을 줄이는 데에도 큰 도움이 된다.

먼저 로우 락(Row Lock)이란?

예를 들어 트랜잭션 A가:

 
UPDATE member
SET name = 'Kim'
WHERE id = 1;
 

를 실행하면

DB는 보통 해당 행(Row)에 락을 겁니다.

member(id=1)
   ↑
 Row Lock
 

그러면 다른 트랜잭션 B는 같은 행을 수정하려고 할 때 대기해야 합니다.


락은 언제부터 걸릴까?

중요한 점은

트랜잭션 시작
 

시점이 아니라

UPDATE SQL 실행 시점
 

부터 걸리는 경우가 많습니다.

예를 들어:

 
@Transactional
public void changeName() {

    Member member = em.find(Member.class, 1L);

    // 비즈니스 로직 10초 수행

    member.setName("Kim");
}
 

JPA의 쓰기 지연 덕분에:

트랜잭션 시작
↓
조회
↓
10초 동안 계산
↓
commit
↓
UPDATE 실행
↓
락 획득
↓
commit 완료
↓
락 해제
 

가 됩니다.


만약 쓰기 지연이 없다면?

가정해봅시다.

 
member.setName("Kim");
 

하는 순간 즉시 UPDATE가 나간다면

트랜잭션 시작
↓
UPDATE 실행
↓
락 획득
↓
10초 동안 계산
↓
commit
↓
락 해제
 

가 됩니다.


그러면 락 유지 시간이

10초
 

가 됩니다.