Mybatis와 @Transactional

Bobby·2023년 3월 9일
0

오답노트

목록 보기
4/6
post-thumbnail

🤢 문제 발생

  • mysql, mybatis 사용중

개요

다음 코드에서 문제점이 무엇이었을까? 바로 안다면 댕고수..

발생 상황 간단히 재구성

  1. DB에는 파일 이름만 저장되어 있다. ex) test.png
  2. prefix는 property로 관리하고 있다. ex) http://test.com
  3. id로 파일 이름을 찾아와서 전체 url을 생성 ex) http://test.com/test.png
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class TestService {

    private final TestMapper testMapper;

    public void test() {
    
        final List<Integer> idList = List.of(1, 2, 3, 1);
        idList.forEach(id -> {
            System.out.println(greetings(id));
        });
    }

    private TestDto greetings(final int id) {
        final String prefix = "http://test.com/";

        final TestDto url = testMapper.getUrl(id);
        url.setUrl(prefix + url.getUrl());
        return url;
    }
}
  • dto
@Data
public class TestDto {

    private String url;
}
  • mapper
<select id="getUrl"
        parameterType="int"
        resultType="com.example.datasource.dto.TestDto">
    SELECT url FROM test WHERE id=#{id}
</select>
  • 데이터

실행

  • 이상한 데이터 발생!!

😯 문제 해결 1

  • 쿼리로그를 찍어봤다.

  • 이상한점 발견..
    마지막 쿼리는 수행되지 않는 것을 확인 했다.

❗️ @Transactional 어노테이션은 같은 조회쿼리를 수행하면 캐싱을 한다!

  • (mysql, mybatis 환경)
  • @Transactional 어노테이션을 제거 하고 실행

😬 문제 해결 2

  • 하지만 해당 메소드가 트랜잭션이 필요한 상황이어서 @Transactional 어노테이션을 제거할 수 없었다.

  • mybatis 옵션에서 캐시를 바로 적용하도록 변경

<select id="getUrl"
        parameterType="int"
        flushCache="true"
        resultType="com.example.datasource.dto.TestDto">
    SELECT url FROM test WHERE id=#{id}
</select>
  • 정상동작

🤑 문제 해결 3

  • 응답객체를 새로 생성하지 않고 같은 객체를 참조 하고 있어서 해당 객체의 필드값을 직접 수정해서 생긴 문제이다.
  • db 응답 객체가 아닌 새로운 DTO를 생성하여 데이터를 담는다.
private TestResponse greetings(final int id) {
    final String prefix = "http://test.com/";

    final TestDto url = testMapper.getUrl(id);

    return new TestResponse(prefix + url.getUrl());
}
  • 정상동작

profile
물흐르듯 개발하다 대박나기

0개의 댓글