Spring 1주차 - Service Layer, Transaction

김건우·2023년 12월 22일

개발 공부

목록 보기
11/13
post-thumbnail

Service Layer

Web Application을 만들기 위한 요구사항

  • 유저 혹은 Frontend Application의 요청을 처리하고, 적절한 응답을 줄 수 있어야 한다.
  • 예외 처리를 할 수 있고, 예외가 발생했을 때 적절한 응답을 줄 수 있어야 한다.
  • 인증과 인가 처리를 할 수 있어야 한다.
  • 비즈니스 로직을 처리할 수 있어야 한다.
  • Transaction 관리 전략이 있어야 한다.
  • 스토리지 및 다른 외부 시스템과 통신할 수 있어야 한다.

Controller와 DTO를 작성함으로써,

  • 유저 혹은 Frontend Application의 요청을 처리하고, 적절한 응답을 줄 수 있어야 한다.
  • 예외 처리를 할 수 있고, 예외가 발생했을 때 적절한 응답을 줄 수 있어야 한다.

두 가지를 구현했다.

Service Layer에서는 세 가지 요구사항을 처리

  • 비즈니스 로직 구현
  • Transaction 경계 설정
  • 예외에 대한 처리

트랜잭션(Transaction)이란?

  • 트랜잭션(Transaction)은 데이터베이스와 같은 지속적인 데이터 저장소에서 수행되는 작업의 논리적인 실행 단위를 나타낸다.
  • 트랜잭션은 여러 단계의 작업을 논리적으로 묶어서 모두 성공할 때만 커밋하고, 하나라도 실패하면 롤백하여 이전 상태로 되돌리는 목적을 가지고 있다. 이는 데이터 일관성을 유지하고 데이터베이스의 무결성을 보장하기 위한 핵심적인 개념 중 하나이다.

트랜잭션의 ACID 특성

  • 원자성(Atomicity)
    • 트랜잭션은 원자적(atomic)이어야 한다. 트랜잭션 내에서 수행되는 모든 작업이 일괄성 있게 수행되거나, 전혀 수행되지 않아야 함을 의미한다.
  • 일관성(Consistency)
    • 트랜잭션이 실행되기 전과 실행된 후에는 일관된 상태를 유지해야 한다.
    • 트랜잭션이 성공적으로 완료되면 데이터베이스는 일관된 상태로 유지되어야 한다. 데이터베이스의 제약이나 규칙을 만족해야한다는 말과 같다.
    • 모든 계좌에는 잔액이 표시되어야 한다 라는 데이터베이스의 제약이 있다고 가정할 때, 계좌의 잔액을 삭제하는 쿼리를 트랜잭션으로 수행을 했을때, 이는 잔액이 표시되어야한다는 잔액을 위반했기 때문에 Consistency가 깨진다고 할 수 있다.
  • 고립성(Isolation)
    • 트랜잭션은 다른 트랜잭션으로부터 격리되어야 한다. 하나의 트랜잭션이 실행 중일 때, 다른 트랜잭션에서는 해당 트랜잭션의 변경 내용을 볼 수 없어야 한다.
    • 예외적으로, 고립성 수준(Isolation Level)을 설정할 순 있습니다.
  • 지속성(Durability)
    • 트랜잭션이 성공적으로 완료되면 그 결과는 영구적으로 저장되어야 한다. 이는 시스템 장애가 발생하더라도 트랜잭션의 결과가 보존되어야 함을 의미한다.

트랜잭션 사용

  • @Transactional 을 클래스나 메소드 앞에 붙여서 사용한다.
    • 클래스 앞에 붙이면 해당 클래스의 하위 메소드까지 모두 적용된다.
  • 하나의 작업단위 에 있어서 일부만 수행되면 안되는 모델에 대해 사용한다.

사용 예시

@Service
class CourseServiceImpl: CourseService {
    override fun getAllCourseList(): List<CourseResponse> {
        // TODO: DB에서 모든 Course를 가져와서 CourseResponse로 변환 후 반환
        TODO("Not yet implemented")
    }

    override fun getCourseById(courseId: Long): CourseResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course를 가져와서 CourseResponse로 변환 후 반환
        TODO("Not yet implemented")
    }

		@Transactional
    override fun createCourse(request: CreateCourseRequest): CourseResponse {
        // TODO: request를 Course로 변환 후 DB에 저장
        TODO("Not yet implemented")
    }

		@Transactional
    override fun updateCourse(courseId: Long, request: UpdateCourseRequest): CourseResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course를 가져와서 request로 업데이트 후 DB에 저장, 결과를 CourseResponse로 변환 후 반환
        TODO("Not yet implemented")
    }

		@Transactional
    override fun deleteCourse(courseId: Long) {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course를 삭제, 연관된 CourseApplication과 Lecture도 모두 삭제
        TODO("Not yet implemented")
    }

}
profile
즐겁게

0개의 댓글