Skip to content

신규 트랜잭션 테스트

스프링 부트에서 예외 발생시 Propagation.REQUIRES_NEW 트랜잭션으로 생성된 데이터는 정상적으로 커밋된 것을 확인하기 위한 테스트

  1. 채번 서비스를 Propagation.REQUIRES_NEW로 설정해서 생성한다.
    UniqueIdService.kt
    @Service
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = [BizException::class])
    class UniqueIdService(private val uniqueIdMapper: UniqueIdMapper) {
    fun generateUniqueId(): String {
    return try {
    var id: String?
    do {
    id = UUID.randomUUID().toString()
    if (uniqueIdMapper.selectUniqueIdCnt(id) > 0) {
    continue
    }
    uniqueIdMapper.insertUniqueId(
    UniqueId(
    id,
    "Y",
    null,
    1000,
    "0:0:0:0:0:0:0:1",
    null,
    1000,
    "0:0:0:0:0:0:0:1"
    )
    )
    break
    } while (true)
    id
    } catch (e: Exception) {
    throw BizException(e)
    }
    }
    }
  2. 롤백 테스트를 하기 위한 API를 생성한다.
    1. 채번을 한다.
    2. 롤백을 확인하기 위한 임시 데이터를 생성한다.
    3. 익셉션을 발생시킨다.
    any service class
    @Service
    @Transactional(rollbackFor = [BizException::class])
    class SpringBootService(
    private val uniqueIdService: UniqueIdService,
    private val photoBoardMapper: PhotoBoardMapper,
    ) {
    fun testGenerateUniqueId(param: PhotoBoard) {
    try {
    photoBoardMapper.insertPhotoBoard(param)
    uniqueIdService.generateUniqueId()
    throw RuntimeException("test")
    } catch (e: Exception) {
    throw BizException(e)
    }
    }
    }
    1. 컨트롤러 코드
    any controller class
    @Operation(summary = "롤백되었을때 별도의 트랜잭션으로 생성된 데이터가 남아있는지 확인하기 위한 테스트", description = "롤백되었을때 별도의 트랜잭션으로 생성된 데이터가 남아있는지 확인하기 위한 테스트 API")
    @PostMapping("/when-exception-occur-another-transaction-commit-test")
    fun testGenerateUniqueId(@Valid @ModelAttribute param: InsertPhotoBoardRequest): ResponseEntity<ResponseDto<Unit>> {
    log.info("testGenerateUniqueId param: $param")
    val model = param.toModel()
    springBootService.testGenerateUniqueId(model)
    return ResponseEntity.status(HttpStatus.CREATED).body((ResponseDto(Unit)))
    }
  3. 테스트 코드를 생성한다.
    any test class
    @DisplayName("롤백되었을때 별도의 트랜잭션으로 생성된 데이터가 남아있는지 확인하기 위한 테스트")
    @Test
    fun `롤백되었을때 별도의 트랜잭션으로 생성된 데이터가 남아있는지 확인하기 위한 테스트`() {
    return Given {
    spec(multipartRequestSpecification)
    formParam("title", "test")
    formParam("content", "test")
    multiPart("photo", "sample2.jpg", readResourceFileAsBytes("sample/image/sample2.jpg"), MediaType.IMAGE_JPEG_VALUE)
    } When {
    post("/spring-boot/when-exception-occur-another-transaction-commit-test")
    } Then {
    statusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR)
    } Extract {
    println(body().asString())
    }
    }
  4. 테스트를 수행한다.
  5. 로그 확인
    1. 데이터 생성 후 예외발생 확인
      1. /*insertPhotoBoard*/
      INSERT INTO T_PHOTO_BOARD ( TITLE
      , CONTENT
      , PHOTO_PATH
      , CREATE_DT
      , CREATE_USER_ID
      , CREATE_IP
      , UPDATE_DT
      , UPDATE_USER_ID
      , UPDATE_IP )
      VALUES ( 'test'
      , 'test'
      , 'http://localhost/photo/sample2.jpg'
      , NOW()
      , 1000
      , '0:0:0:0:0:0:0:1'
      , NOW()
      , 1000
      , '0:0:0:0:0:0:0:1' )
      {executed in 13 msec}
      2026-02-11 10:29:24,959 [DEBUG] [http-nio-auto-1-exec-1] n.s.l.l.s.Slf4jSpyLogDelegator: com.zaxxer.hikari.pool.ProxyStatement.getGeneratedKeys(ProxyStatement.java:230)
      1. getGeneratedKeys on query: /*insertPhotoBoard*/
      INSERT INTO T_PHOTO_BOARD ( TITLE
      , CONTENT
      , PHOTO_PATH
      , CREATE_DT
      , CREATE_USER_ID
      , CREATE_IP
      , UPDATE_DT
      , UPDATE_USER_ID
      , UPDATE_IP )
      VALUES ( 'test'
      , 'test'
      , 'http://localhost/photo/sample2.jpg'
      , NOW()
      , 1000
      , '0:0:0:0:0:0:0:1'
      , NOW()
      , 1000
      , '0:0:0:0:0:0:0:1' )
      {executed in 0 msec}
      2026-02-11 10:29:24,965 [INFO ] [http-nio-auto-1-exec-1] n.s.l.l.s.Slf4jSpyLogDelegator:
      |--------------|
      |generated_key |
      |--------------|
      |1049 |
      |--------------|
      2026-02-11 10:29:24,979 [DEBUG] [http-nio-auto-1-exec-1] n.s.l.l.s.Slf4jSpyLogDelegator: com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
      2. /*selectUniqueIdCnt*/
      SELECT COUNT(0) AS CNT
      FROM T_UNIQUE_ID
      WHERE UNIQUE_ID = '8bee1528-7592-410d-aa9a-0be0e5680955'
      {executed in 4 msec}
      2026-02-11 10:29:24,985 [INFO ] [http-nio-auto-1-exec-1] n.s.l.l.s.Slf4jSpyLogDelegator:
      |----|
      |cnt |
      |----|
      |0 |
      |----|
      2026-02-11 10:29:24,993 [DEBUG] [http-nio-auto-1-exec-1] n.s.l.l.s.Slf4jSpyLogDelegator: com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
      2. /*insertUniqueId*/
      INSERT INTO T_UNIQUE_ID ( UNIQUE_ID
      , USE_YN
      , CREATE_DT
      , CREATE_USER_ID
      , CREATE_IP
      , UPDATE_DT
      , UPDATE_USER_ID
      , UPDATE_IP )
      VALUES ( '8bee1528-7592-410d-aa9a-0be0e5680955'
      , 'Y'
      , NOW()
      , 1000
      , '0:0:0:0:0:0:0:1'
      , NOW()
      , 1000
      , '0:0:0:0:0:0:0:1' )
      {executed in 4 msec}
      2026-02-11 10:29:25,067 [ERROR] [http-nio-auto-1-exec-1] b.m.c.c.e.a.RestApiExceptionAdvice: ### BizException occurred
      java.lang.RuntimeException: test
      at biz.mintchoco.carrot.api.spring_boot.service.SpringBootService.testGenerateUniqueId(SpringBootService.kt:21)
      ...
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
      at java.base/java.lang.Thread.run(Thread.java:1583)
      {"payload":null,"isSuccess":false,"resultCode":"FAILURE","message":"test"}
    2. T_PHOTO_BOARD 테이블에 생성된 데이터가 롤백된 것을 확인
      [2026-02-11 10:35:50] carrot> select * from T_PHOTO_BOARD where PHOTO_BOARD_ID = 1049
      [2026-02-11 10:35:51] 503 ms (execution: 15 ms, fetching: 488 ms)에서 0개 행 불러옴
    3. T_UNIQUE_ID 테이블에 생성된 데이터는 남아있는것을 확인
      [2026-02-11 10:37:45] carrot> select * from T_UNIQUE_ID where UNIQUE_ID = '8bee1528-7592-410d-aa9a-0be0e5680955'
      [2026-02-11 10:37:46] 513 ms (execution: 19 ms, fetching: 494 ms)에서 1부터 1개 행을 불러왔습니다