결론
spring에서 대소문자 구분을 하지 않도록 하여 통과하였습니다.
공식문서 내용중 ""(따옴표로 이스케이프)되지 않은것은 대문자로 변경하여 실행한다는것을 보고 이로인하여 문제가 발생했다고 판단하였고 ""로 감싸지 않은 것들도 쿼리 그자체로 실행될 수 있도록 수정하였습니다(대문자로 변경하여 실행되지 않도록 하였습니다)
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
'JPA > ORM JPA' 카테고리의 다른 글
JPA auditing, baseEntity를 활용하여 Soft delete 구현 (1) | 2023.08.09 |
---|
댓글