[Spring] 프로젝트 트랜잭션 설정

심주흔·2023년 12월 25일
1

springboot3

목록 보기
3/7
post-thumbnail

트랜잭션
일정 구간의 동작들이 모두 성공해야하는 일련의 과정으로, 쪼갤 수 없는 업무 처리의 최소 단위 / 보통 서비스 파일에서 관리함.

롤백
트랜잭션 내부에서 실행에 실패하면 지금까지 수행한 것을 모두 폐기하고 진행 초기 단계로 되돌리는 것

@Transactional
트랜잭션의 어노테이션으로 해당 어노테이션이 선언된 메서드를 트랜잭션으로 묶는 것. 클래스에 선언하면 클래스의 모든 메서드별로 각각 트랜잭션이 부여 됨. 실해하면 롤백하여 처음으로 돌아감

🧬 트랜잭션 실습하기

시나리오

  • 블로그 프로젝트에 데이터 3개를 한번에 생성요청하기
  • 데이터를 DB에 저장하는 과정에서 의도적으로 오류 발생시키기(id = -1)
  • 어떻게 롤백 되는지 확인하기

🦠 블로그 프로젝트에 데이터 3개를 한번에 생성요청하기

🧪 Controller

@PostMapping("/api/transaction-test")
public ResponseEntity<List<Article>> transactionTest(@RequestBody List<ArticleForm>dtos){

}

@PostMapping 으로 생성 요청을 접수한다.
데이터 3개를 받을 transactionTest()라는 메서드를 만든다.
REST API 방식으로 POST 요청을 받기 위해 @RequestBody 어노테이션을 사용한다.
서버에서 응답을 할 때 데이터 생성 결과뿐만 아니라 상태 코드도 함께 보내주기 위해서 반환형은 ResponseEntity<List<Article>> 로 한다.

 List<Article> createdList = articleService.createArticles(dtos);
        return (createdList != null) ? ResponseEntity.status(HttpStatus.OK).body(createdList) : ResponseEntity.status(HttpStatus.BAD_REQUEST).build();

createdList 라는 메서드는 Service에 만들고 동작하게 할 것이라 가정하고 미리 호출할 반환값을 createdList에 저장하도록 한다.

🧪 Service

과정

  • dto 리스트를 엔티티 리스트로 변환하기
  • 엔티티 리스트를 DB에 저장하기
  • 에러 발생시키기
  • 결과 값 반환하기

🌡️ 스트림 문법1 (dto List -> entity List로 변환)

stream 문법
리스트와 같은 자료구조에 저장된 요소를 하나씩 순회하면서 처리하는 코드 패턴이다.

List<Article> articleList = new ArrayList<>;
for (int i = 0; i < dtos.size(); i++) {
	ArticleForm dto = dtos.get(i);
    ArticleForm entity = dto.toEntity();
    articleList.add(entity);

위 코드는 dto 리스트를 엔티티 리스트로 변환하는 코드인데 이 코드를 stream() 문법을 사용하면 아래와 같이 코드 길이를 줄일 수 있다.

  // dto 묶음을 엔티티 묶음으로 변환하기
        List<Article> articleList = dtos.stream()
                .map(dto -> dto.toEntity())
                .collect(Collectors.toList());

🌡️ 스트림 문법2(Entity List를 DB에 저장하기)

스트림 문법을 사용하지 않을 때

for(int i = 0; i < articleLsit.size(); i++){
	Article article = articleList.get(i);
    articleRepository.save(article);
}

스트림 문법을 사용할 때

// 엔티티 묶음을 DB에 저장하기
        articleList.stream().forEach(article -> articleRepository.save(article));

🌡️ 예외 발생시키기

 //강제 예외 발생시키기
        articleRepository.findById(-1L)
                .orElseThrow(()-> new IllegalArgumentException("결제 실패!!"));

id 값이 -1인 데이터를 찾는다. JPA로 자동 생성된 id 값은 양수이므로 음수가 될 수 없다. orElseThorw() 메서드로 IllegalArgumentException을 발생시키는데 "결제실패"라는 메시지도 함께 출력되기를 바란다. orElseThorw() 는 메서드 값이 존재하면 그 값을 반환하고, 그렇지 않으면 전달값으로 보낸 예외를 발생시킨다.

🌡️ 결과값 반환하기

//결과 값 반환하기
        return articleList;

🧪 트랜잭션 설정하기

간단하게 서비스 코드에 어노테이션만 추가하면 된다.

🧬 결과

기존에 있는 데이터를 GET하여 확인함.

데이터를 넣고 싶은데 500 서버 에러가 발생한다.


결제 실패 메시지도 한번에 확인할 수 있다.

트랜잭션을 사용하지 않았다면 오류는 발생하지만 데이터는 정상적으로 들어가지는 현상이 발생할 수 있으며, 이는 프로젝트를 유지하는게 큰 장애가 발생할 수도 있다. 모든 동작이 정상적으로 동작해야하는 최소한의 단위가 있다면 트랜잭션을 적극적으로 활용해보자.

profile
이봐... 해보기는 했어?

1개의 댓글

comment-user-thumbnail
2023년 12월 30일

뒤지실래요? 눈삽으로 맞아보셨어요?

답글 달기