본문 바로가기
Error 정리

[토이 프로젝트 WST] JPA 적용 오류(h2 DB에서 TABLE 생성하지 못할 때)

by 집돌이디벨로퍼 2024. 6. 6.

오늘 JPA를 처음으로 적용시켜봤다 구글링해서 나온 예시를 하나 잡아서 DB에 적용이 되나 테스트부터 해봤다.

 

1.첫 번째는 Table 생성 오류였다.  (파악하는데 오래 걸림)

could not prepare statement [Table "TESTY" not found (this database is empty); SQL statement:

=>분명 TESTY Table 이 생성이 되야 하는데 전혀 생성이 되지 않고 있었다..

 

여러가지 구글링을 해봤으나 h2 호환성 문제일수도 있다는 글들을 보고 머리아파지기 시작했지만 일단 호환성 문제는 배제하고 ChatGPT, 구글링, OverStackFlow 등 곳곳에서 검색해 문제를 알아보았다 그결과

 spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/postgres
    username: postgres
    password: 951951
    driver-class-name: org.postgresql.Driver
  h2:
    console:
      enabled: true # H2 DB 웹콘솔 사용하도록 설정 (http://localhost:8080/h2-console)
  jpa:
    database: postgresql
    database-platform: org.hibernate.dialect.PostgreSQLDialect
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
        format_sql: true
        show_sql: true
    hibernate:
      ddl-auto: none
    open-in-view: false
    
======================================================================================
수정후
======================================================================================
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/postgres
    username: postgres
    password: 951951
    driver-class-name: org.postgresql.Driver
  h2:
    console:
      enabled: true # H2 DB 웹콘솔 사용하도록 설정 (http://localhost:8080/h2-console)
  jpa:
    database: postgresql
    database-platform: org.hibernate.dialect.PostgreSQLDialect
    properties:
      hibernate:
        ddl-auto: create-drop
        dialect: org.hibernate.dialect.PostgreSQLDialect
        format_sql: true
        show_sql: true
    defer-datasource-initialization: true
    open-in-view: false

여기서 맨 아랫줄에서 두번째 줄에 있는 ddl-auto : none 때문에 테이블이 생성이 안되는 것이었다! 게다가 정의하는 곳도 제대로 읽어보지도 않고 hiberate 부분을 중복되게 막 써둔 것이었다 이러면 yml을 사용하는 보람이 없는데.. 아무튼 여기서 한 3시간 정도 애먹은 것 같아서 힘들었다.. 그래도 여러가지 글들을 찾아보다 에러잘보는 팁도 얻어서 기분이 나쁘지만은 않다.

 

 

2. 두 번째는 메서드 네임드 쿼리 문제였다. 분명 이제 테이블 생성까지는 되는 것 같은데 또 에러가 났다. 메서드 이름은 findFirst2ByUserNameLikeOrderByIDDesc에서 UserName, ID 이렇게 정의해놓고 정작 Testy 클래스에는 ID가 아닌 id라고 정의를 해놨다..

@Entity
@Getter
@Setter
public class Testy {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "user_name")
    private String userName;
}

============================================================================
수정후
============================================================================
@Entity
@Getter
@Setter
@Table(name = "testy")
public class Testy {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_code")
    private Integer ID;
    @Column(name = "user_name")
    private String userName;
}

private long id <-- 이렇게 적어놨다 이러니 쿼리랑 달라서 당연히 오류가 나지.. 테이블 어노테이션과 컬럼 어노테이션은 문제해결을 위해 발버둥친 흔적이다ㅎ;

@Repository
public interface TestyRepository extends JpaRepository<Testy, Integer> {
    List<Testy> findFirst2ByUserNameLikeOrderByIDDesc(String name);
}

 

이렇게 하니 에러 문구가 살짝 달라지는 것을 느낄 수 있었다

Hibernate: 
    insert 
    into
        testy
        (user_name) 
    values
        (?) 
    returning user_code
2024-06-06T21:10:21.873+09:00  WARN 50340 --- [projecttry] [    Test worker] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 42000, SQLState: 42000
2024-06-06T21:10:21.873+09:00 ERROR 50340 --- [projecttry] [    Test worker] o.h.engine.jdbc.spi.SqlExceptionHelper   : Syntax error in SQL statement "insert into testy (user_name) values (?) [*]returning user_code"; SQL statement:
insert into testy (user_name) values (?) returning user_code [42000-224]

could not prepare statement [Syntax error in SQL statement "insert into testy (user_name) values (?) [*]returning user_code"; SQL statement:

3. 세 번째 문제코드

org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement [Syntax error in SQL statement "insert into testy (user_name) values (?) [*]returning user_code"; SQL statement:

chatgpt의 문제해결 제안

"returning user_code" 구문이 PostgreSQL에서 발생하는 문제와 관련이 있습니다. PostgreSQL에서 generated by default as identity를 사용할 때, Hibernate가 "returning" 구문을 적절히 처리하지 못할 때 발생합니다. 이를 해결하기 위해 몇 가지 방법을 제안합니다.

GenerationType.IDENTITY 대신 GenerationType.SEQUENCE 사용

먼저, @GeneratedValue 어노테이션을 GenerationType.SEQUENCE로 변경하여 시퀀스를 사용하도록 설정할 수 있습니다. PostgreSQL에서 시퀀스는 더 잘 지원됩니다.

왜그런지 모르겠지만 returning 구문을 적절히 처리하지 못한다니.. 

 

Testy 클래스의 @GeneratedValue 의 Strategy 문제였다! Testy클래스에서 ID로 정의한(user_code) 컬럼은 자동생성되는 컬럼으로 @Id,@GeneratedValue 두개의 어노테이션이 필요했는데 여기서 나는 Strategy가 무슨역할을 하는지도 모르고 냅다 쓰기만 해서 문제가 발생된거였다..

 

GenerationType.IDENTITY와 GenerationType.SEQUENCE의 차이점

주요 차이점 요약

  1. 키 생성 방식:
    • IDENTITY: 데이터베이스의 자동 증가 기능을 사용.
    • SEQUENCE: 데이터베이스의 시퀀스 객체를 사용.
  2. 퍼포먼스 및 트랜잭션:
    • IDENTITY: 데이터 삽입 시 키가 생성되므로, 삽입 전에 키 값을 알 수 없음.
    • SEQUENCE: 데이터 삽입 전에 키 값을 미리 가져올 수 있음.
  3. 데이터베이스 종속성:
    • IDENTITY: 키 생성이 데이터베이스에 의존적.
    • SEQUENCE: 시퀀스 객체를 지원하는 데이터베이스에서 사용 가능.

이거 까지 수정해서 결국 테스트 성공..

 

findAllTest
findFirst2ByUserNameLikeOrderByIDDesc("kim%")

 

하아 오늘 해결 못할 줄 알았는데 해결해서 너무 다행이다

 

 

 

 

 

 

 

문제 해결 능력 키우는 방법

출처:https://kth990303.tistory.com/423

 

[ERROR] JPA initializationError 해결 방법 모음 및 대처법

스프링 프레임워크에서 JPA ORM을 이용하면 반드시 한 번쯤은 만날 수밖에 없는 에러가 있다. could not prepare statement; SQL; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement org.spr

kth990303.tistory.com