JPA/ORM JPA

JPA, H2 데이터 베이스 대소문자 구분에러

Lahezy 2023. 5. 12.
728x90

결론

spring에서 대소문자 구분을 하지 않도록 하여 통과하였습니다.

 

공식문서 내용중 ""(따옴표로 이스케이프)되지 않은것은 대문자로 변경하여 실행한다는것을 보고 이로인하여 문제가 발생했다고 판단하였고  ""로 감싸지 않은 것들도 쿼리 그자체로 실행될 수 있도록 수정하였습니다(대문자로 변경하여 실행되지 않도록 하였습니다)

 

h2 데이터 베이스 docs

spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=FALSE

을 추가하고 기존에 수행하려던 코드(대소문자를 구분하지 않는 코드)

@SQLDelete(sql = "UPDATE member SET activated = false WHERE member_id = ?")

로 수정하여

테스트 케이스를 통과하였습니다.

 

 


문제 발견

soft delete를 제공하려고 엔티티단에서 UPDATE를 실행하는데 문제가 발생했습니다.

2023-05-08T21:10:13.581+09:00  WARN 8666 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 42103, SQLState: 42S03
2023-05-08T21:10:13.592+09:00 ERROR 8666 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Table "MEMBER" not found (candidates are: "member"); SQL statement:
UPDATE member SET activated = false WHERE member_id = ? [42103-214]

org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [UPDATE member SET activated = false WHERE member_id = ?]

	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:257)

분명 member 인데 MEMBER이 없다고 나오는것을 확인할 수 있습니다.

1차 수정 : 테이블 이름 지정 

테이블 이름을 지정하여 봤지만  그래도 오류가 계속 나왔습니다.

 

2차 수정 :  컬럼에서 대소문자를 비교

Query자체에서 대소문자를 구분하니 테스트 케이스가 통과 된것을 확인할 수 있었습니다.

 


제가 해결한 방법(위에 결론과 같은 내용입니다)

http://www.h2database.com/javadoc/index.html

boolean databaseToUpper
Database setting DATABASE_TO_UPPER (default: true).

위에처럼 컬럼 마다 ""를 넣는 방법도 있지만 저의 경우 프로퍼티 파일에서  DATABASE_TO_UPPER=FALSE 를 추가하였습니다.

H2데이터 베이스에서 기본적으로 따옴표가 없는 이름들은 대문자로 변경되지만 해당 코드를 추가하면 따옴표가 없는 경우 대문자로 변경하지 않는다는 의미입니다. 즉 대소문자를 구분하지 않겠다는 의미입니다. => 따라서 Update member에서 member 테이블이 MEMBER로 변화한 것이라 생각할 수 있습니다.

 

spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=FALSE

을 추가하고 기존에 수행하려던 코드(대소문자를 구분하지 않는 코드)

@SQLDelete(sql = "UPDATE member SET activated = false WHERE member_id = ?")

로 수정하여

테스트 케이스를 통과하였습니다.

 

문제 발생 이유(왜 jpa 쿼리 같은 다른것은 잘 되었는데 이것만 그랬을까)

spring.config.activate.on-profile=test

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

logging.level.org.springframework.boot.autoconfigure=ERROR

#Hibernate에서 예약어를 자동으로 이스케이핑
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.properties.hibernat.dialect=org.hibernate.dialect.H2Dialect

 

저의 수정 전 테스트 프로퍼티 파일입니다.

#Hibernate에서 예약어를 자동으로 이스케이핑
spring.jpa.properties.hibernate.globally_quoted_identifiers=true

이 코드는 무슨 일을 하는지 확실히 모르고 추가 하였습니다.

알고 보니 Hibernate가 데이터베이스 식별자를 따옴표로 묶어서 사용하도록 하는 설정이고 대소문자 구분이 안 되는 데이터베이스에서는 오류가 발생할 수 있다.(대소문자를 구분하게 되었다)라는 것을 알게 되었습니다. => 그래서 조회 시에 ""를 넣은 경우 통과가 된 것이라 생각했습니다. [[기존 쿼리들은 하이버네이트에서 따옴표로 이스케이핑 하여 실행하였지만, 위의 쿼리는 네이티브 쿼리 그 자체를 실행했다고 생각했습니다]]

 

그래서 이번에는 제거하고 실행해 보았습니다.

좌 : 이스케이핑 코드를 추가한 경우 ""로 둘러져 있는것을 볼 수 있다.
제거 전
제거 후

제거후에는 ""로 감싸지 않은 코드도 테스트 코드를 잘 통과하는것을 확인할 수 있었습니다.

 

 

아래의 내용은 조사하여 작성하였지만 틀릴 수 있습니다. 이후에 추가로 틀린 부분을 알게 되면 수정하겠습니다.

더보기

spring.jpa.properties.hibernate.globally_quoted_identifiers=true 는  예약어를 자동으로 이스케이핑하는 코드로 Hibernate에서 SQL 쿼리를 생성할 때 사용되는 옵션으로 식별 키워드를 ""로 묶어준다. 해당 코드를 추가하면서 따옴표를 하게 되어서 발생했던 문제였던 것이다.  => 그래서 조회 시에 ""를 넣은 경우 통과가 된 것이다.

 

DATABASE_TO_UPPER=FALSE  H2 데이터베이스에서 대소문자를 구분하지 않도록 하는 코드로 데이터베이스에서 쿼리를 실행할 때 사용되는 으로 대소문자를 구분하지 않는다. 따라서 기존에 ""가 붙어있지 않던 네이티브 쿼리 문자가 원래는 대문자로 변경되어 실행되었는데 소문자로 인지할 수 있게 된 것이다. 

 

위의 코드만 보면 idetifiers 코드만 제거하면 통과하지만 나의 경우  spring.jpa.properties.hibernate.globally_quoted_identifiers=true코드와

 DATABASE_TO_UPPER=FALSE를 모두 추가한 코드를 사용하였다. 기존에 코드에서 h2데이터 베이스 예약어를 사용하는 코드가 있기에 사용해야 한다.(삭제하면 다른 테스트 코드가 통과하지 못한다)

 

그래서 위 두 가지를 함께 사용하여 예약어는 이스케이 핑되지만 대소문자는 구분되지 않게 하여 사용할 수 있다.

 

네이티브 쿼리는 ""없이 실행되어 다르게 처리된다.  (기존 코드들은 ""로 감싸져서 소문자 그 자체로 잘 동작했지만 위의 네이티브 쿼리는 ""로 감싸져있지 않아서 대문자로 변경되어 쿼리가 처리되었다)

 

 

 

참고 

https://blog.ycpark.net/entry/H2-Console-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

https://kindloveit.tistory.com/85

https://madplay.github.io/post/how-to-escape-a-column-name-with-spring-data-jpa

https://docs.spring.io/spring-boot/docs/3.1.0/reference/htmlsingle/#data.sql.jpa-and-spring-data.creating-and-dropping

http://www.h2database.com/javadoc/index.html

728x90

'JPA > ORM JPA' 카테고리의 다른 글

JPA auditing, baseEntity를 활용하여 Soft delete 구현  (1) 2023.08.09

댓글