프로젝트를 진행하는 과정에서 H2 데이터베이스 환경에서 해당 코드를 작성했을 때 정상적으로 쓰기 작업이 수행되었다
@Transactional(readOnly = true)
public WalkResponse getWalk(Member member) {
Walk walk = walkRepository.findByMember(member)
.orElseThrow(() -> new DataNotFoundException("해당되는 id의 산책 경로가 존재하지 않습니다."));
updateSlopes(walk);
return new WalkResponse(
walk.getId(),
walk.getMaxSlope(),
walk.getAvgOfSlope(),
walk.getUpdateDateTime(),
walk.getWalk()
);
}
@Transactional
public void updateSlopes(Walk walk) {
MapResponse mapResponse = mapService.getFitness(walk.getWalk().coordinates());
walk.updateSlopes(
mapResponse.maxSlope(),
mapResponse.avgOfSlope(),
LocalDateTime.now()
);
}
알고 있는 정보에 따르면 @Transactional(readOnly = true) 로 설정을 하고 그 내부에서 메서드를 호출했을 때에는 readOnly = true 속성이 전파된다.
그렇기 때문에 flush가 되지 않고 쓰기 작업은 이루어질 수 없다.

공식문서 내용이다. readOnly 자체는 쓰기 작업을 막는 역할이 아니라 단지 hint를 제공하는 것이라는 내용이다.
그럼 이렇게 힌트를 던져줬을 때 다양한 DB 벤더사들은 이걸 어떻게 처리하느냐가 다를 수 있다는 것이다.
h2 database의 구현 내용이다.
/**
* According to the JDBC specs, this setting is only a hint to the database
* to enable optimizations - it does not cause writes to be prohibited.
*
* @param readOnly ignored
* @throws SQLException if the connection is closed
*/
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("setReadOnly(" + readOnly + ')');
}
checkClosed();
} catch (Exception e) {
throw logAndConvert(e);
}
}
readOnly 힌트를 무시한다고 되어있다.
그래서 코드를 조금 수정을 해보았다.
@Transactional(readOnly = true)
public WalkResponse getWalk(Member member) {
Walk walk = walkRepository.findByMember(member)
.orElseThrow(() -> new DataNotFoundException("해당되는 id의 산책 경로가 존재하지 않습니다."));
updateSlopes(walk);
return new WalkResponse(
walk.getId(),
walk.getMaxSlope(),
walk.getAvgOfSlope(),
walk.getUpdateDateTime(),
walk.getWalk()
);
}
private void updateSlopes(Walk walk) {
MapResponse mapResponse = mapService.getFitness(walk.getWalk().coordinates());
walk.updateSlopes(
mapResponse.maxSlope(),
mapResponse.avgOfSlope(),
LocalDateTime.now()
);
}
이런 식으로 코드를 고쳐봤을 때에도 API를 호출할 때마다 업데이트가 정상적으로 이루어졌다.
@Transactional 의 readOnly 옵션은 쓰기 작업을 막는 역할이 아니라 힌트를 제공하는 역할인데, 벤더사마다 해당 힌트를 처리하는 방식이 다르다.
현재 개발 및 테스트 환경에서 사용하는 h2 데이터베이스의 경우에는 해당 힌트를 무시한다고 적혀있다.
테스트 할 때에는 업데이트 간격을 제거하고 업데이트가 정상적으로 작동하는지만 보는데, 간격을 설정하고 배포를 했을 때에는 어떻게 될 지 모르는 일이었다.
특히나 로컬에서는 h2를 사용하고 배포 환경에서는 MySQL을 사용하기 때문에 이러한 문제는 더더욱 조심해야겠다고 생각했다.
+) 실제로 실행을 해보지는 않았지만, 찾아본 바로는 MySQL 환경에서는 해당 작업이 실패한다고 한다.
+) 이 부분에 대해서 멘토님께 조언을 구해보았는데, 개발 환경이나 운영 환경이나 같은 DB 벤더사를 사용하는 것이 최선이라고 하셨다. RDS를 사용하는데 public으로 돌린 경우에 비용문제가 발생해서 운영 환경에서는 MySQL, 개발 환경에서는 H2를 사용하게 된게 화근이었던 것 같다.