김영한님의 수업에서 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
여기서 또 다시 드는 의문점은
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