[Spring Boot] JdbcSQLSyntaxErrorException: Syntax error in SQL statement ... expected "identifier" 해결

Jiwoo Kim·2021년 6월 21일
6

오류 로그

목록 보기
2/2
post-thumbnail

스프링 부트와 AWS로 혼자 구현하는 웹 서비스를 혼자 따라하면서 공부하는 중인데, JPA repository를 테스트하다가 아래와 같은 에러가 났다.

에러 메세지

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "
    CREATE TABLE POST (
       ID BIGINT NOT NULL AUTO_INCREMENT,
        AUTHOR VARCHAR(255),
        CONTENT VARCHAR(255) NOT NULL,
        TITLE VARCHAR(500) NOT NULL,
        PRIMARY KEY (ID)
    ) ENGINE=[*]INNODB"; expected "identifier"; SQL statement:

상황

테스트 코드

@ExtendWith(SpringExtension.class)
@DataJpaTest
public class PostRepositoryTest {

    @Autowired
    PostRepository postRepository;

    @Test
    public void 게시글저장_불러오기() throws Exception {
        // given
        String title = "테스트 게시글";
        String content = "테스트 본문";
        String author = "test_author@gmail.com";
        postRepository.save(Post.builder()
                .title(title)
                .content(content)
                .author(author)
                .build());

        // when
        List<Post> postList = postRepository.findAll();

        // then
        assertThat(postList.size()).isEqualTo(1);
        Post post = postList.get(0);
        assertThat(post.getTitle()).isEqualTo(title);
        assertThat(post.getContent()).isEqualTo(content);
        assertThat(post.getAuthor()).isEqualTo(author);
    }
}

간단한 Post 객체 하나 만들어서 저장하고, 조회하는 테스트였는데, 이걸 실행하니까 에러가 났다.

applications.properties

# sql 보기
spring.jpa.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

# h2 문법을 mysql로 변경
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

# 테이블 자동생성
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

H2 in-memory 데이터베이스로 간단하게 테스트를 하는 중이었기 때문에 dialect만 지정해주고 다른 구체적인 설정은 하지 않았다. 근데 저 MySQL5InnoDBDialect만 설정하면 에러가 터졌다.

삽질

에러 메세지에서 expected identifier.. 어쩌구 하길래, 예약어가 잘못 사용되었거나, h2 ↔ MySQL 문법 간 변환에 오류가 있었구나 싶었다. 그래서 관련 해결책을 구글링하고 적용했는데, 계속 똑같은 에러 메세지만 떴다.

우선, config에 아래 것들을 추가했다.

spring.datasource.url=jdbc:h2:~/test;MODE=MySQL;DATABASE_TO_LOWER=TRUE

MySQL 모드로 지정하는 파라미터를 url에 지정해줬다. 소용없었다.

spring.jpa.properties.hibernate.globally_quoted_identifiers=true

예약어를 quoted 처리하기 위해 자동으로 작은 따옴표를 붙여 주는 설정을 추가했다. 소용없었다.

에러 메세지는 예약어 관련이라고 했는데, JPA, MySQL, H2 문서를 뒤져봐도 모든 필드와 테이블 이름은 예약어가 아니었다. 한 시간동안 구글링을 더 해봐도 에러 메세지조차 변하지 않고 해결이 안돼서 겁나 짱났다.

해결

혹시나 하면서 테스트 클래스의 @DataJpaTest 어노테이션을 @SpringBootTest로 변경해봤다.


@ExtendWith(SpringExtension.class)
@SpringBootTest
public class PostRepositoryTest {
	// ...
}    

그랬더니 테스트가 통과했다..^^ 테이블도 잘 생성되고 조회도 잘 됐다..

사실 이 코드 작성하기 전에 @SpringBootTest@DataJpaTest의 차이점을 알아 보려다가~~ 넘 내용이 방대하고 복잡해보여서 일단 책부터 마무리하려고 했다. 근데 역시 대충대충 넘어가려다가 피보는 건 미래의 나인가보다...^^ 제때제때 모르는 것들 제대로 알고 넘어가자는 교훈을 얻었다....ㅎ...두 어노테이션의 차이는 여기에 정리했다.

암튼 그래서 @DataJpaTest@SpringBootTest의 차이점을 공부하면서, @DataJpaTest를 썼을 때 왜 제대로 작동하지 않는지 알아봤다. 결론적으로, @DataJpaTest@AutoConfigureTestDatabase가 config에 있는 H2 DB가 아닌, EmbeddedDatabaseConnection에 설정된 임시의 H2 DB를 호출해서 문제가 발생한 것이었다. 이 때 H2의 url은

"jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", (url) -> url.contains(":h2:mem")

이렇게 설정되어 있다. 여기에 MODE=MySQL이 없어서 MySQL 문법으로 쿼리를 날리면 오류가 발생한 것이다.

결론

  1. H2를 MySQL 모드로 사용하려면 application.properties에 아래 설정을 추가해야 한다.
spring.datasource.url=jdbc:h2:~/dbname;MODE=MySQL;DATABASE_TO_LOWER=TRUE
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
  1. 내가 설정한 DB를 사용해서 @DataJpaTest를 진행하려면, @AutoConfigureTestDatabasereplace=NONE으로 변경해야 한다.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class SomeRepositoryTest {
	// ...
}

2개의 댓글

comment-user-thumbnail
2022년 6월 25일

와.. 도움 많이 받았습니다 감사합니다!

답글 달기
comment-user-thumbnail
2022년 10월 11일

감사합니다 적게 일하고 많이버세요!

답글 달기