@Transactional을 경계로 다음과 같은 동작의 차이가 있다.
하나의 경계를 두고 두개의 다른 관심사가 충돌하는 예시를 보자.
예시로 코드를 보며 설명해 보겠다.
다음과 같이 Response 를 반환하는 상황을 가정하자.
@Transactional
public Dto updateParent(Long id) {
Praent p = repository.find(id);
p.update();
return new Dto(p);
}
반환되는 Dto 구조는 다음과 같다.
class Dto {
private String name;
private LocalDateTime updatedAt;
private Integer version;
private List<Child> childs;
public Dto(Parent p) {
name = p.name();
updatedAt = p.updatedAt();
version = p.version();
childs = p.childs();
}
}
Dto 안에서 childs를 LazyLoading 해오기 위해선, Dto가 트랜잭션 바운더리 안에 있음을 인지하고 코딩해야 한다.
이정도는 기술적 한계를 인정하고 그냥 쓰면 된다.
하지만 문제는 updatedAt이 갱신되지 않는다는 점이다. (version도)
plush가 되지 않은 상태에서 복사를 했기 때문이다.
Dto 생성을 Service 밖에서 만드는것도 생각해볼수 있다.
이땐 또 LazyLoading이 동작하지 않는다.
Transactional은 굉장히 침투적이라고 생각한다.
코드가 추가되는 등의 직접적인 침투는 없지만, 절차가 진행되는 사이사이 깊게 관여한다.
Dto 변환을 어디서 해야 하느냐는 매번 고민인데, 이러지도 저러지도 못하게 만든다.
어찌보면 엔티티를 불완전한 상태로 돌아다니게 만드는 LazyLoading이 문제일수도 있다.
LazyLoading을 포기하고 항상 Dto생성을 Transactional 밖에서 생성하면 되겠다 ㅎㅎ
는 말이 안된다.
@Transacitonal도 LazyLoading도 너무나 유용하기에 쓰지말자는 규칙을 만들순 없다.
근데 요런 내용을 언제 한번 썼던것 같기도 한데..
매번 불편해서 끄적거리다 마는것 같아서 헷갈린다 ㅎㅎ