이 어노테이션이 붙으면 스프링은 해당 타깃을 포인트 컷의 대상으로 자동 등록하며 트랜잭션 관리 대상이 된다. 즉, 이 어노테이션을 통해 포인트 컷에 등록하고 트랜잭션 속성을 부여하는 것이다.
트랜잭션 어노테이션을 테스트에 붙이면 테스트의 DB 커밋을 롤백해주는 기능이 있다.
@Transactional
DB와 연동되는 테스트를 할 때에는 DB의 상태와 데이터가 상당히 중요하다.
하지만 문제는 테스트에서 DB에 쓰기 작업을 하면 DB의 데이터가 바뀌는 것인데, 트랜잭션 어노테이션을 테스트에 활용하면 테스트를 진행하는 동안에 조작한 데이터를 모두 롤백하고 테스트를 진행하기 전의 상태로 만들어준다. 어떠한 경우에도 커밋을 하지 않기 때문에 테스트가 성공하거나 실패해도 상관이 없으며 심지어 예외가 발생해도 어떠한 문제가 발생하지 않는다. 강제로 롤백시키도록 설정되어 있기 때문이다.
2023-02-16 18:17:01.094 INFO 5328 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@58ce9668 testClass = DataRestTest, testInstance = com.fastcampus.projectboard.controller.DataRestTest@b1d7b09, testMethod = givenNothing_whenRequestingArticles_thenReturnsArticlesJsonResponse@DataRestTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@172b013 testClass = DataRestTest, locations = '{}', classes = '{class com.fastcampus.projectboard.FastCampusProjectBoardApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@51dcb805, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@4b3fa0b3, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@50ad3bc1, [ImportsContextCustomizer@56673b2c key = [org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration, org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration, org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityConfiguration, org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@47987356, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@611889f4, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@741a8937, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@2781e022], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@16eb01d4]; rollback [true]
Hibernate:
select
article0_.id as id1_0_,
article0_.created_at as created_2_0_,
article0_.created_by as created_3_0_,
article0_.modified_at as modified4_0_,
article0_.modified_by as modified5_0_,
article0_.content as content6_0_,
article0_.hashtag as hashtag7_0_,
article0_.title as title8_0_
from
article article0_ limit ?
Hibernate:
select
count(article0_.id) as col_0_0_
from
article article0_
2023-02-16 18:17:01.509 DEBUG 5328 --- [ main] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/hal+json', given [*/*] and supported [application/hal+json]
2023-02-16 18:17:01.544 DEBUG 5328 --- [ main] m.m.a.RequestResponseBodyMethodProcessor : Writing [PagedModel { content: [EntityModel { content: Article(id=1, title=Quisque ut erat., content=Vestibul (truncated)...]
2023-02-16 18:17:01.642 INFO 5328 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@58ce9668 testClass = DataRestTest, testInstance = com.fastcampus.projectboard.controller.DataRestTest@b1d7b09, testMethod = givenNothing_whenRequestingArticles_thenReturnsArticlesJsonResponse@DataRestTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@172b013 testClass = DataRestTest, locations = '{}', classes = '{class com.fastcampus.projectboard.FastCampusProjectBoardApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@51dcb805, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@4b3fa0b3, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@50ad3bc1, [ImportsContextCustomizer@56673b2c key = [org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration, org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration, org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityConfiguration, org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@47987356, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@611889f4, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@741a8937, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@2781e022], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]
위의 코드를 보면 첫줄과 마지막 줄에 TranscationContext가 열리고 TranscationContext가 닫히는 것을 볼 수 있다.
하지만 테스트 메소드 안에서 진행되는 작업을 하나의 트랜잭션으로 묶고는 싶지만 강제 롤백을 원하지 않을 수 있다. 테스트의 작업을 그대로 DB에 반영하고 싶다면 @Rollback(false)를 이용해주면 된다. @Rollback은 메소드에만 적용가능하므로, 클래스 레벨에 부여하기를 원한다면 @TransactionConfiguration(defaultRollback=false) 를 이용하고, 롤백을 원하는 메소드에 @Rollback(true)를 이용하면 된다.