시리즈 게시글
Wednesday, June 07, 2023
#daily
TODOs
- Transaction 과 코드의 호환을 어떻게 할지 고민 #develop
WORKs
TILs
- Transaction Level 과 Abstraction Level 을 동일하게 가져갈 수 있는가?
^(?<!.*@Transactional\(readOnly = true\)\n).*@EnableReadReplica
^(?<!.*@EnableReadReplica\n).*@Transactional\(readOnly = true\)\n(?!.*@EnableReadReplica\n)
Transaction 어떻게 처리할까
Transaction
을 좁게/넓게 잡고 싶은 니즈는 항상 존재한다.
- 좁게 잡고 싶은 경우 -> Transaction 안에서 Network I/O 등의 I/O Intensive 한 작업들이 일어날 경우, 배치잡과 같이 트랜잭션이 너무 길게 잡히는 경우
- 넓게 잡고 싶은 경우 -> Atomic 한 처리가 필요한 경우 (조회 -> 업데이트가 원자적으로 일어나야 하는
이런 문제를 해결하려면
- Transaction 을 처리하는 코드를 한 Abstraction Level 로 몰아넣는 것이 쉬운 해결책이다. (이 코드에서만 적절한 트랜잭션 범위를 신경쓰고, 자식들에게는 더이상 트랜잭션을 가져오는 책임을 전파하지 않는다.)
suspend fun transactionManagementLayer() {
val resultA = withTx {
aService.getAFromDB()
}
val resultB = bService.getBFromNetwork(resultA)
val resultC = withTx {
cService.getCFromDB(resultB)
}
return resultC
}
fun asdf() = withTx {
transactionTemplate.execute {
}
}
하지만 이렇게 될 경우, 트랜잭션을 더 좁게 (더 하위의 Service 에서) 잡고 싶은 상황을 핸들링하지 못한다.
좁게 잡을 이유가 있는가? 는 또 다른 문제일 듯.
// `getAFromDB`, `getBFromNetwork`, `getCFromDB` 를 묶어서 실행하는 함수 `getABC` 를 만들고 싶을 때 이를 적절히 핸들링하지 못한다.
sus
context(DoNotTransactionMe)
suspend fun getABC() {
val resultA = withTx { getAFromDB() }
val resultB = getBFromNetwork(resultA)
val resultC = withTx { getCFromDB(resultB) }
return resultC
}
fun bigggMethod() {
withTx {
getABC()
getDFG()
}
}
어쨌든 이렇게 더 좁게 잡고 싶은 상황을 해결하려면 더 coarse 한 Tx 핸들링이 필요한 순간이 찾아온다고 볼 수 있고, 이를 위해서는 아래와 같은 해결책이 필요하다.
- 최초인입
- 유저
U5WTGQN34BXISZEL
- 유저
U2SQWLJF8YDPJJ
Notes created today
List FROM "" WHERE file.cday = date("2023-06-07") SORT file.ctime asc
Notes last touched today
List FROM "" WHERE file.mday = date("2023-06-07") SORT file.mtime asc
<< [[2023-06-06-Tuesday|Yesterday]] | [[2023-06-08-Thursday|Tomorrow]] >>