김영한님의 수업에서 JPA 실습을 해보던 중 아래와 같은 에러가 발생하였습니다.

javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement

 

위의 에러 내용을 보면 Column "MEMBER0_.USER_NAME" not found; SQL statement: 라는 문구를 볼 수 있습니다.

 

그래서 몇가지 의심되는 부분에 대해 해결해봤습니다.

 

1. Member class 에 Column을 잘못 설정했는지 확인

: 테이블에 컬럼명을 이미 만들어 둔 상태기때문에 @Column으로 이름을 정해줘서 사용하는데, 이때 오타가 있나 확인해봤습니다.

 

 => 정상인 것으로 확인

 

2. application.properties 에 jpa 설정 제대로 추가해줬는지 확인 ( 해결 )    --> 아래 내용 읽어보기

spring.jpa.hibernate.ddl-auto = create

원래 create가 아닌 none으로 설정해줬었는데 이 부분에서 오류가 나고 있었습니다.

원래 제가 이해한 바로는 create는 객체에 대한 테이블과 테이블의 컬럼명을 자동으로 생성해주기때문에 저는 none을 사용했습니다.

그런데 이 부분에 대해 오류가 나고 있었던걸 보아 다시 개념을 확실히 잡고 넘어가야 할것 같습니다.

https://tjdwns4537.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F 

 

TISTORY

나를 표현하는 블로그를 만들어보세요.

www.tistory.com

 

여기서 또 다시 드는 의문점은

create를 해주고 다시 none을 해준 후 테스트를 해보면 되는 것입니다.

그래서 테이블을 직접 확인해보니 phonenumber이였던 컬럼명이 phone_number이 되어있었습니다.

그래서 테이블을 삭제 후 다시 테스트를 해보던 중 아래와 같은 사실을 알게 되었습니다.

 

Member class에 각 객체에 @Column 으로 이름을 설정해줬는데

이때 @Column(name="phoneNumber") 로 설정을 하니까 PHONE_NUMBER로 읽고 PHONE_NUMER 컬럼을 찾으려고하니

에러가 발생하고 있던것입니다.

그래서 @Column(name="phonenumber")라고 설정하니 ddl-auto = none을 하고도 에러발생하지 않았습니다.

spring.jpa.hibernate.ddl-auto = none

이 외에도 column명을 설정할때 전부 대문자로 해도 에러는 발생하지 않습니다.

단지 소문자뒤에 대문자가 오면 구분자로 (_) 가 들어간다는 것입니다.

 

그래서 다시 확인을 해보니 다음과 같은 규칙이 있었습니다.

 

 

ㅇ JPA의 기본 테이블 DDL Naming 전략

 기본적으로 JPA는 DDL을 진행할 때 Entity 이름과 해당 필드들을 lower_under_score 방식을 이용합니다.

 예를 들어, @Column(name="PARK") 를 하면 Table에는 park로 lowerCarmelCase 를 lower_snake_case로

 변환하여 테이블을 생성합니다.

 

 이는 중요한 문제입니다.

 그 이유는 MySQL 에서 쿼리를 날릴 때에 [ 문자의 대소문자를 확실히 구분하는 설정 ] 과 [ 그렇지 않은 설정 ] 이

 있기 때문에 만약 확실히 구분하는 설정일 경우에 에러가 발생합니다.

 

 

* 해결 방법

SpringPhysicalNamingStrategy를 상속받아 Custom하여 설정값으로 물려주는 방법입니다.

 

1) 상속받는다.

2) 오버라이딩하여 함수를 작성해준다.

public class UpperCaseNamingStrategy extends SpringPhysicalNamingStrategy {

    @Override
    protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
        return new Identifier(name.toUpperCase(), quoted); // 파라미터로 넘어온 name값을 대문자화 시킵니다.
    }
}

3) UpperCaseNamingStrategy 클래스를 application.yml에 설정해줍니다.

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: web.common.strategy.UpperCaseNamingStrategy # 커스텀클래스 패키지

 ==> 확인해보면 UPPER_SNAKE_CASE가 적용된 모습을 볼 수 있습니다.

 

 

 

 

- 결론

1) 애초에 컬럼명을 설정할 때, 대문자나 소문자 하나로 설정한다.

2) UpperCaseNamingStrategy 클래스를 이용한다.

 

 

 

 

* 링크

https://velog.io/@devduhan/Spring%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-JPA-Naming-%EC%A0%84%EB%9E%B5

 

+ Recent posts