문제 현상
간단한 POST API 호출 이후 (회원가입) entity -> dto 변환 시 id가 반영되지 않는 문제가 발생하였다.
@PostMapping()
fun createMember(@Valid @RequestBody dto: SignupRequest): ApiResponse<MemberResponse> {
val createdMember = memberService.createMember(dto)
return ApiResponse.success(MemberResponse.from(createdMember))
}
@Transactional
fun createMember(dto: SignupRequest): Member {
val member = Member(
nickname = dto.nickname,
name = dto.name,
password = dto.password?.let { passwordEncoder.encode(it) },
email = dto.email,
profileImage = dto.profileImage
)
val savedMember = memberRepository.save(member)
return savedMember
}
id가 반영되지 않았다는 것은 DB에도 저장이 되지 않았다는 의미였고 DDL상에서 auto_increment 옵션이 없다던가 하는 문제도 없었다.
실례지만... 어데 트씹니꺼?
따라서 트랜잭션이 정상적으로 활성화 되어있는지? 살펴보기 위해 아래와 같이 로그를 추가해두었다.
@Transactional
fun createMember(dto: SignupRequest): Member {
println(AopUtils.isAopProxy(memberRepository))
println("트랜잭션 활성화 여부: ${TransactionSynchronizationManager.isActualTransactionActive()}")
val member = Member(
nickname = dto.nickname,
name = dto.name,
password = dto.password?.let { passwordEncoder.encode(it) },
email = dto.email,
profileImage = dto.profileImage
)
val savedMember = memberRepository.save(member)
return savedMember
}
프록시, 트랜잭션 모두 활성화되어 있다는 로그를 확인하였으나 여전히 save가 작동하지 않았다.
따라서 saveAndFlush 메서드로 수정해서 테스트를 진행해보았다.
@Transactional
fun createMember(dto: SignupRequest): Member {
println(AopUtils.isAopProxy(memberRepository))
println("트랜잭션 활성화 여부: ${TransactionSynchronizationManager.isActualTransactionActive()}")
val member = Member(
nickname = dto.nickname,
name = dto.name,
password = dto.password?.let { passwordEncoder.encode(it) },
email = dto.email,
profileImage = dto.profileImage
)
val savedMember = memberRepository.save(member)
return savedMember
}
no transaction is in progress
saveAndFlush로 고쳤으나 이제 트랜잭션 상태가 이상하다는 것을 꺠닫고 열심히 구글링 해보았다.
한 github issue에서
spring:
jpa:
open-in-view: false
hibernate:
ddl-auto: update
properties:
hibernate:
allow_update_outside_transaction: true
위와 같이 allow_update_outside_transaction를 true로 설정하면 된다는 것을 보고 true로 설정하고 다시 테스트 해보았다.
true로 설정하고 나니 정상적으로 insert되고 API도 정상 응답된 것을 확인하였다.
다만, 이는 임시적인 해결책이고 save() 호출 및 해당 옵션을 활성화 하지 않아도 작동하게끔 수정해야한다.
따라서 현재 문제 상황은 다음과 같다.
메서드 | allow_update_outside_transaction: true | allow_update_outside_transaction: false |
---|---|---|
save() | X | X |
saveAndFlush() | 정상 작동 (DB에 insert됨) 즉시 flush 수행하여 DB 반영 |
X |
따라서 saveAndFlush 상태에서 allow_update_outside_transaction: true로 하였을 시에만 정상 작동하는 것을 보고 어떤 설정에서 트랜잭션이 가로채기 당하고 있다는 느낌이 들었다.
따라서 transactionManager를 검색해보니
@Configuration
@EnableBatchProcessing
class BatchConfig(private val dataSource: DataSource) {
@Bean
@Primary
fun batchTaskExecutor(): TaskExecutor {
val executor = SimpleAsyncTaskExecutor("batch-executor-")
executor.concurrencyLimit = 10
return executor
}
@Bean
fun transactionManager(): PlatformTransactionManager {
return DataSourceTransactionManager(dataSource)
}
그냥 같은 폴더에 Spring batch Config를 설정해두었었는데 transactionManager를 여기서 정의하고 있어서 그랬다.. ;;
메서드마다 서로 다른 트랜잭션 매니저를 쓰기때문에 트랜잭션이 제대로 작동하지 않았던 문제였다.