Spring Boot

[Spring Boot] Transaction

안도일 2023. 3. 17. 23:08

스프링 부트에서 Transaction은 데이터베이스 작업을 수행하는데 필요한 일련의 작업들을 하나의 논리적인 작업 단위로 묶어서 원자성(Atomicity), 일관성(Consistency), 독립성(Isolation), 지속성(Durability)을 보장하는 것을 말한다.

Transaction은 다수의 데이터베이스 작업을 하나의 논리적인 작업으로 묶어서, 모두 성공하면 DB에 반영하고, 하나라도 실패하면 모든 작업을 취소(롤백)하여 데이터 일관성을 유지한다.

 

스프링 부트에서 @Transactional 어노테이션을 사용해 Transaction을 설정할 수 있다. 이를 통해 데이터베이스의 일관성을 유지하고, 예외가 발생하는 경우 롤백하도록 설정할 수 있다.

 

예를 하나 들어보자. 사용자가 인터넷 쇼핑몰에서 5만 원짜리 니트를 결제하려고 한다. 쇼핑몰은 결제 요청을 받은 후 데이터베이스에서 해당 제품의 재고를 1개 삭제시키고, 결제를 진행하려 한다. 하지만 사용자의 잔고에 3만 원 밖에 들어있지 않아 결제가 취소되었다.   이 상황에서 데이터베이스에서 이미 1개의 재고를 삭제시켰으니 난감한 상황이다. 만약 이 과정이 Transaction으로 묶여있었다면 결제가 취소된 순간 데이터베이스에서 1개의 재고를 삭제시킨 작업도 취소될 것이다.

 

한번 코드로 작성해 보자.

 

Controller

 

 

Service

 

 

오랜만에 보는 문법이 있네요;

 

첫 번째 줄 코드 리뷰

해당 코드는 dtos 리스트의 각 요소를 dto.toEntity() 메서드를 사용하여 Article Entity 객체로 변환하고 이를 List <Article> 형태로 반환하는 기능을 수행한다.
Stream.map() 메소드를 사용하여 dtos 리스트의 요소를 하나씩 dto 변수에 바인딩하고, dto.toEntity() 메소드를 호출하여 Article 엔티티 객체로 변환한다.
이렇게 변환된 Article Entity 객체들은 Stream.collect() 메소드를 사용하여 List<Article> 형태로 수집된다.
Stream API를 이용하여 코드를 작성하였기 때문에 각 요소들에 대한 연산을 병렬로 처리할 수 있다. 이는 대량의 데이터를 처리할 때 성능적인 이점을 가져올 수 있다.

 

두 번째 줄 코드 리뷰

해당 코드는 articleList 리스트의 각 요소인 Article Entity 객체들을 forEach() 메서드를 사용하여 하나씩 꺼내어 articleRepository.save() 메소드를 호출하는 기능을 수행한다.

Stream.forEach() 메서드는 Stream 객체의 각 요소들을 반복하면서 인자로 전달받은 람다식을 적용한다. 이 코드에서는 articleList 리스트의 각 요소인 Article Entity 객체들을 forEach() 메서드를 사용하여 하나씩 꺼내고 이를 articleRepository.save() 메소드를 사용하여 DB에 저장한다.

 

해당 Transaction은 전달받은 JSON 데이터들을 DTO로 변환한 후 다시 Entity로 변환시켜  DB에 저장하는 로직에 일부러 예외를 발생시킨 것이다.

데이터를 DB에 저장을 다 한 후에 예외를 발생시켰을 때 DB를 살펴보자.

 

 

 

이미 DB에 데이터를 다 저장한 후에 예외가 발생했으니 DB에 데이터가 있어야 하지만 저장되지 않고 기본 데이터만 존재한다.