TransactionalEventListener
가 동작을안한다!!!그러니깐 내가 원하는대로 동작을 하지않는다. 이벤트 리스너에서 데이터 변경이 반영되지 않는다...
간단한 코드를 보겠다.
GroupService.kt
에서 Group
을 삭제하고 삭제 이벤트를 발행한다. /**
* GroupService.kt
*/
@Transactional
fun deleteGroupPublish(id: Long){
groupRepository.deleteById(id)
applicationEventPublisher.publishEvent(
DeleteGroupEvent(id)
)
}
Group
에 속하는 GroupMember
를 삭제한다. /**
* GroupMemberService.kt
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
fun deleteGroupMemberEventHandler(event: DeleteGroupEvent){
groupMemberRepository.deleteByGroupId(event.id)
}
@SpringBootTest
class GroupServiceTest{
@Autowired
lateinit var groupService: GroupService
@Autowired
lateinit var groupRepository: GroupRepository
@Autowired
lateinit var groupMemberRepository: GroupMemberRepository
@Test
fun delete_group_and_publish_event(){
// given
val group = groupRepository.save(Group())
val groupMember = groupMemberRepository.save(GroupMember(group.no))
// when
groupService.deleteGroup(group.no)
// then
val groupList = groupRepository.findAll()
val groupMemberList = groupMemberRepository.findAll()
assertThat(groupList).isEmpty()
assertThat(groupMemberList).isEmpty()
}
}
그러니깐 ORM 에 등록해서 데이터베이스가 실제로 변경되게 하려면commit
,rollback
등의 기능이 되어야하고, 그걸 편하게 하기위해서TransactionManager
인터페이스가 존재하고, 이걸 대부분 구현해놓은AbstractPlatformTransactionManager
추상클래스가 존재하고, 이걸 또 각자 사용하는 ORM에서TransactionManager
를 구현해놓았는데...
나중에 블로그를 따로 정리하겠다.
구글링으로 좀 이것저것 찾아봤었는데 여기 블로그를 좀 참고했다.
일단 내부구조를 슥 한번 보겠다.
변경사항이 반영되는doCommit()
을 실행하는 부분은 여기 한군데 밖에 없다
AbstractPlatformTransactionManager
클래스의 processCommit()
메서드이다.
코드를 보아 status.isNewTransaction()
이 true 여야 doCommit()
이 실행되어 데이터베이스 변경이 반영할수있다는걸 알수 있다.
그렇다면 status.isNewTransactiion()
의 상태값이 세팅 부분을 찾아보겠다.
동일한 클래스의 getTransaction()
에서 현재 실행중인 Transaction
이 새로운 트랜잭션인지 분기한다는걸 확인했다.
현재 Transactional
의 propagation이 기본값 (Propagation.REQUIRED)
으로 되어있으니 하단의 조건문에 걸려 트랜잭션을 시작하게 된다.
그리고 해당 메서드는 트랜잭션을 생성하며 newTransaction
이 true로 들어가는걸 확인할수 있다.
AbstractPlatformTransactionManager 클래스의 processCommit()
메서드의 status.isNewTransaction()
이 true 로 들어갈수가 있겠다.
(중복된 사진)
동일하게 getTransaction()
으로 현재 트랜잭션의 상태값을 받아오는건 동일하지만, 상위 클래스에서 전파된 트랜잭션이 존재하기 때문에 handleExistingTransaction()
메서드를 타게 된다.
그리고 handleExistingTransaction
내부를 확인하면 definition.getPropagationBehavior()
에 따라서 트랜잭션의 newTransaction
의 상태값이 다르게 들어가는걸 확인할수 있다.
그리고 해당 값의 기본값은 Transactional의 기본값인 REQUIRED
PROPAGATION_REQUIRED
상태값을 따라가면 마지막에 newTransaction
이 false 로 생성되게 되고 아까 확인했었던 commit이 일어나지 않게 된다.
상위클래스에서 전파된 트랜잭션은뭐 그거대로 두고 새로운 트랜잭션을 열면 된다.
아까 확인했었던 handleExistingTransaction
에서 트랜잭션 PROPAGATION
이 REQUIRES_NEW
라면 최초에 트랜잭션을 열때와 동일하게 여는 방식을 사용하는걸 볼수 있다.
그렇지만 여기 블로그 도 한번 확인해보도록 하자.