Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- 로그
- aws
- MongoDB
- 로그 시스템
- iam user 새성
- Redis
- AWS IAM
- TDD
- 에러 모니터링
- gradle
- iam user
- 예외 처리
- 테스트 주도 개발
- SENTRY
- Exception
- nosql
- 카카오 소셜 로그인 에러 #카카오 소셜로그인 redirect #카카오소셜로그인 프런트 연동 에러
- java
- exceptionHandler
- aws 접근 권한
- jpa
- @Transactional
- crud-update
- spring
- Spring Boot
- error
- SQL
Archives
- Today
- Total
zini's blog
CRUD - UPDATE 방법 비교 본문
엔티티 조회 후 수정 vs 쿼리문으로 수정
- 기본적인 crud 중 수정시, 엔티티 조회를 통해 객체를 가져와 수정하는 방법과, 쿼리문을 통해 update하는 방법의 차이가 뭘까? 그리고 어떤 방법을 사용해야 할까?
(공부하며 작성한 글이라 틀린 부분이 있을 수 있습니다!)
1. 엔티티 조회 후 수정 (Dirty Checking)
📌 작동 방식 - (@Transactional사용한 경우로 설명)
- 엔티티를 DB에서 조회한 후, 해당 엔티티의 값을 변경함.
- JPA의 Dirty Checking(변경 감지)을 통해 트랜잭션 커밋 시점에 수정된 내용을 DB에 반영함.
🧩 코드 예시
@Transactional
public void updateOrder(Long orderId) {
// 엔티티 조회
Order order = orderRepository.findById(orderId).orElseThrow();
// 상태 업데이트
order.updateStatus(USER_CANCELLED);
// 명시적으로 save 호출 (선택사항- 안써도 영속성 컨택스트에 의해 저장됨)
Order modifiedOrder = orderRepository.save(order);
// 결과 반환
return OrderResponseDto.fromWithoutOrderDetail(modifiedOrder);
}
⚙️ 작동 과정 정리
- 엔티티 조회 (findById)
- orderRepository.findById(orderId)로 DB에서 Order 엔티티를 가져옴.
- 이때 JPA는 *영속성 컨텍스트(Persistence Context)에 엔티티를 관리 상태로 등록
- 엔티티 값 변경 (updateStatus)
- order.updateStatus(USER_CANCELLED); 호출 시 객체의 필드 값이 메모리에서 변경됨.
- 이때 아직 데이터베이스에는 아무 변화 없음!
- 변경 감지 (Dirty Checking)
- 트랜잭션이 끝나기 전에 JPA가 *영속성 컨텍스트에서 관리 중인 엔티티의 변경 내용을 감지
- 변경된 필드를 추적하여 적절한 UPDATE 쿼리를 생성
- 저장 (save)
- orderRepository.save(order); 호출은 사실 선택 사항.
- 이미 영속성 컨텍스트에서 엔티티가 관리되고 있다면 save 없이도 변경 내용이 반영됨
- 다만 save() 호출은 코드를 읽는 사람에게 "변경이 끝났으니 저장하겠다"는 명확한 의도를 전달하는 역할이 될 수 있음
- 트랜잭션 종료 및 커밋
- 메서드가 끝나면서 트랜잭션이 종료되고 커밋이 발생.
- JPA는 이때 변경 내용을 DB에 반영하기 위해 UPDATE 쿼리를 실행.
🔎 내부에서 발생하는 DB 쿼리 흐름
SELECT * FROM orders WHERE order_id = ?
UPDATE orders SET status = ? WHERE order_id = ?
✅ 장점
- 객체 지향적 코드 작성 가능
- 여러 값 변경 시 하나의 트랜잭션으로 관리 가능
- 영속성 컨텍스트 활용으로 최적화 (변경 사항만 쿼리 전송)
❌ 단점
- 엔티티 조회 과정 필요 → 성능 이슈
- 데이터가 많아질수록 메모리 사용량 증가
- 복잡한 쿼리 작업에는 비효율적
2. 쿼리문으로 수정 (@Modifying + @Query)
📌 작동 방식
- JPA Repository에서 직접 JPQL 또는 Native Query를 사용해 즉시 DB 데이터를 수정함.
🧩 코드 예시 - Repository
@Transactional
@Modifying
@Query("UPDATE Order o SET o.status = :status WHERE o.orderId = :orderId")
public void updateOrderStatus(@Param("orderId") Long orderId, @Param("status") String status);
⚙️ 작동 과정
- 쿼리가 작성된 메서드 호출 시 DB로 즉시 쿼리 전송
- @Modifying + @Query 메서드는 실행 즉시 쿼리가 DB로 전송되어 데이터가 변경됨
- DB 수정 작업 즉시 실행
- 트랜잭션 커밋 시 변경 사항 유지 (메서드 실패시 - 롤백되어 취소됨)
✅ 장점
- 엔티티 조회 과정 없이 바로 DB 수정 가능 → 성능 향상
- 대량 데이터 업데이트에 유리
- 복잡한 조건으로 쿼리 작성 가능
❌ 단점
- 객체 지향적인 코드 작성 어려움
- 영속성 컨텍스트와 동기화되지 않음 → 데이터 일관성 문제 가능성
- 쿼리 작성의 복잡성 증가
cf) 트랜잭션(@Transactional)과 save()의 관계
1. 트랜잭션(@Transactional)의 역할
- 트랜잭션이 있어야 JPA가 *변경 감지(Dirty Checking)를 수행하고, 트랜잭션이 커밋될 때 변경 내용을 DB에 반영함
- 트랜잭션이 없으면 메서드가 끝나도 JPA가 데이터를 실제로 DB에 반영할 기회가 없음.
- 트랜잭션과 커밋 시점 정리
- 트랜잭션 시작 (@Transactional)
- 메서드가 호출되면 트랜잭션이 시작됨. 이때 데이터베이스에 반영되지 않고 메모리(트랜잭션 컨텍스트)에서 모든 작업이 대기함.
- 쿼리 실행 (Dirty Checking)
- Dirty Checking: 엔티티 변경은 트랜잭션 종료 직전까지 메모리에서 감지되며 최종적으로 쿼리를 생성
- 커밋 시점 (트랜잭션 성공 시)
- 메서드가 정상적으로 종료되면 커밋(Commit) 이 발생하며 DB에 변경 사항이 확정됨.
- 이때 이전에 실행된 쿼리(업데이트) 유지됨.
- 롤백 (트랜잭션 실패 시)
- 메서드 실행 중 예외가 발생하면 롤백(Rollback)됨.
- 이미 실행된 쿼리(UPDATE, DELETE 등)도 모두 취소됨.
- 트랜잭션 시작 (@Transactional)
2. save() 메서드의 역할
- save()를 호출하면 엔티티가 즉시 영속성 컨텍스트에 반영되며, DB에 INSERT 또는 UPDATE 쿼리가 실행됨.
- 트랜잭션이 없더라도 save는 명시적으로 DB 커넥션을 통해 작업을 요청함.
3. 결론: 트랜잭션과 save()의 동작
트랜잭션 | save() 호출 | DB 반영 여부 |
❌ 없음 | ❌ 호출 안 함 | 🚫 반영 안 됨 |
❌ 없음 | ✅ 호출 | ✅ 반영됨 |
✅ 있음 | ❌ 호출 안 함 | ✅ Dirty Checking 반영됨 |
✅ 있음 | ✅ 호출 | ✅ 반영됨 |
- @Transactional 없이도 save()가 있다면 DB에 반영된다.
- 하지만 Dirty Checking은 @Transactional이 있어야만 작동한다.
- 따라서 실무에서는 @Transactional을 붙이는 것이 권장되며, 명시적인 save() 호출은 유지 보수에 따라 적절히 선택하는 것이 좋다!
🔄 비교 요약
항목 | 엔티티 조회 후 수정 (with @Transactional) | 쿼리문으로 수정 |
작동 방식 | Dirty Checking | 즉시 쿼리 실행 |
엔티티 조회 필요 여부 | 필요 | 불필요 |
DB 쿼리 전송 시점 | 트랜잭션 커밋 시 | 메서드 실행 즉시 |
성능 | 데이터 많을 때 비효율적 | 성능 우수 |
복잡한 조건 처리 | 어려움 | 용이 |
트랜잭션 커밋 영향 | 커밋 성공 시 변경 적용 | 동일 |
객체 지향 코드 작성 | 용이 | 어려움 |
🚀 결론
- 단순 수정이나 엔티티 간 연관성 유지가 필요한 경우 → 엔티티 조회 후 수정(Dirty Checking)
- 대량 데이터 수정 또는 복잡한 조건 기반 작업 → 쿼리문으로 수정
'프로젝트 > 하우키키 : 고객 응대 챗봇' 카테고리의 다른 글
00. [졸업 프로젝트-스타트] Howkiki 프로젝트 (0) | 2024.11.26 |
---|