오늘 CodeKata는 1문제를 풀었다. 재귀를 활용하는 문제였는데, 생각보다 답이 바로 떠올려지지 않아서 시간을 많이 잡아먹었다. 약간 시간이 남아서 2번째 문제도 풀려고 했었지만, 생각보다 어렵고 코드가 계속 헷갈려서 다음으로 미뤘다. 좀 더 생각을 해보자.
드디어 JPA 심화 강의를 다 들었다. 이번 강의는 이전에 들었던 강의보다 꽤 만족스럽다. Docker 관련 강의는 이해가 안 되는 부분이 많아서 강의자료를 몇 번씩 들여다봐야해서 다소 불만족스러웠지만, 이번 강의는 기억두면 좋을만한 것들이 꽤 있었다.
일단 Transactional에 propagation 타입에 대해 배웠다. propagation 타입은 required, requires_new, mandatory, nested, never, supports, not_supported 등이 있다. 이 중, 강의에서는 required, requires_new, not_supported 를 강조하였기에 여기서도 이 3가지만 적는다. 부모 트랜잭션은 @Transaction이 붙은 메소드이고, 자식 트랜잭션은 @Transaction이 붙은 메소드가 호출하는 새로운 트랜잭션이다.
required는 default로 작동하며, 부모 트랜잭션이 없으면 새롭게 생성하고, 있으면 부모 트랜잭션에 합류할 때 사용한다.
requires_new는 부모 트랜잭션과 관계없이 새로운 트랜잭션을 생성할 때 사용한다.
not_supported는 부모 트랜잭션이 있으면 해당 트랜잭션을 보류하고 트랜잭션 없이 실행하고, 부모 트랜잭션 없이 실행하도, 동일하게 트랜잭션 없이 실행한다.
기억해 둘 만한 것은 또 있다. AOP는 내부호출을 할 수 없다는 것을 알게 되었다. 이것은 반드시 기억을 해두자, 내부호출을 해결하기 위해서는 여러 방법이 있지만, 가장 좋은 방법은 리팩토링을 하는 것이다. 후에, 내부호출을 발생하지 않도록 코드를 수정해보도록 하자.
JPA에서의 영속성 컨텍스트의 특성으로 인해 발생할 수 있는 트러블도 배웠다. JPQL은 1차 캐쉬를 거치지 않고, 데이터베이스에 직접적으로 영향을 미친다. 이러한 특징으로 인해서 JPQL로의 Delete 혹은 Update와 Repository의 메소드를 혼용을 하였을 때, 내가 원하지 않는 방향으로 코드가 흘러갈 가능성이 높다.
예를 들어서 데이터베이스에 직접적으로 데이터를 수정이나 삭제를 했고, findbyId를 사용해서 데이터를 조회를 했다면, findById가 갱신되지 않은 1차 캐쉬를 참조해서 원하는 데이터를 얻을 수 없다.
이러한 큰 문제를 해결하기 위해선 간단한 해결책이 있는데, JPQL을 통한 Update/Delete 를 하고 1차 캐쉬를 비우는 것이다. 사용하자마자, EntityManager.clear()를 사용해서 1차 캐쉬를 비우거나 JPA repository에서 JPQL을 사용할 경우, Update/Delete를 할 떄 붙이는 @Modifying에 clearAutomatically를 true로 두면 된다. 밑의 코드는 강의자료에 있던 코드이다.
@Repository
interface TodoRepository : JpaRepository<Todo, Long> {
@Modifying(clearAutomatically = true)
@Query("UPDATE Todo todo SET todo.isComplete = :isComplete WHERE todo.id = :todoId")
fun updateIsComplete(todoId: Long, isComplete: Boolean)
}
이제 연휴에 돌입한다. 편히 푹 쉬고 팀 프로젝트에 대비하자
'부트캠프 일지' 카테고리의 다른 글
부트캠프 54일차 후기 (0) | 2024.02.14 |
---|---|
부트캠프 53일차 후기 (0) | 2024.02.13 |
부트캠프 51일차 후기 (1) | 2024.02.07 |
부트캠프 50일차 일지 (1) | 2024.02.06 |
부트캠프 49일차 후기 (1) | 2024.02.05 |