PostgreSQL JDBC Driver가 createClob() is not yet implemented 라고 드러누울 때

spring_pgsql.png
다니는 회사의 주요 고객사가, 업무 중요도가 낮은 시스템에는 PostgreSQL을 사용하는 관계로,  일에서 MySQL은 써 본 적 없지만 PostgreSQL은 썼다. 더불어 실제로도 PostgreSQL(이하 pgsql)이 괜찮은 DBMS라 PC에 깔아 놓고 코딩할 때 사용하고 있다.

증상

Spring Boot도 안 익숙하고, 하는 김에 곧 나올 2.0으로 배우려는 목적으로, ‘스프링부트로 웹서비스 구축하기‘라는 글을 Spring Boot 2.0 기반으로 바꿔 돌려 보고 있다. Hibernate를 구현체로 쓰는 Spring  Boot Starter JPA + H2 Database(in-memory db) 기반의 코드를 작성 및 테스트 통과하고 이 코드를 MariaDB에서 돌렸더니 한 방에 테스트를 통과했다. ‘역시 DB 독립적인 코딩을 하려면 ORM이여~’ 어쩌구 하면서 이 코드를 pgsql에서 돌리는 순간, 난생 처음 보는 Exception이 나면서 테스트 통과하는데 실패했다. 정말 해 보기 전엔 모른다.

Caused by: java.sql.SQLFeatureNotSupportedException: Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.
    at org.postgresql.Driver.notImplemented(Driver.java:683) ~[postgresql-42.2.1.jar:42.2.1]
    at org.postgresql.jdbc.PgConnection.createClob(PgConnection.java:1252) ~[postgresql-42.2.1.jar:42.2.1]
    ... 91 common frames omitted

멘붕이었다.

‘헐~. 정말 createClob() 메소드를 구현 안하고 JDBC 드라이버를 낸 거야?’

원인

믿을 수가 없어 pgsql의 JDBC Driver(이후 pgJDBC) 소스를 봤다. (버전은 42.2.1)

@Override
public Clob createClob() throws SQLException {
  checkClosed();
  throw org.postgresql.Driver.notImplemented(this.getClass(), "createClob()");
}

‘어처구니가 없구먼?’

해결책

9.3-1104-jdbc41 버전의 pgJDBC를 쓰면 된다. 그런데 pgJDBC 버전만 내리고 Hibernate Dialect를 “명시”하지 않을 경우 Hibernate Dialect를 못 찾겠다는 Exception이 터지면서 테스트를 실패한다.

Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
 at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:100)
 at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:54)

즉 spring boot 애플리케이션 설정 파일 (yml 형식을 썼다)에 다음과 같이 Hibernate Dialect를 명시하는 것도 필요하다.

spring: 
    jpa:
        database-platform: org.hibernate.dialect.PostgesSQL95Dialect

H2, MariaDB는 Hibernate Dialect를 명시하지 않아도 문제 없다. 사실 Spring Boot의 디자인 철학이 CoC(Convention Over Configuration)이기도 하고.

PostgreSQL Korea 관리자이신 김상기 님 도움으로 취소선 그은 것보다 더 우아한 해결책을 찾아 수정한다. spring boot 애플리케이션 설정에

spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false

property를 추가하면, 최신 pgJDBC Driver 사용도 가능하고, hibernate dialect 명시적 선언도 불필요하다. yml 형태의 sping boot 애플리케이션 설정은 아래와 같다.

spring:
  jpa:
    properties:
      hibernate:
        temp:
          use_jdbc_metadata_defaults: false

hibernate.temp.use_jdbc_metadata_defaults 프로퍼티 설명 및 디폴트 값은 Hibernate 5.2
User Guide의 Configuration 장(章)
을 참고하시라. (한 줄 써 있어서 도움 될 지 모르겠지만…)

 

유의 사항

Spring Boot 버전 번호 보면 알겠지만 이 버전은 RC1이므로 향후 이 문제가 안 생길 수도 있다. 이후에 이 글 내용이 쓸모 없어질 수 있다. 그런 의미에서 본 글 작성과 관련된 기반 소프트웨어 버전을 명시함으로써 혼란을 방지하고자 한다. & 이 글 쓴 날짜도 꼭 유념해 주셨으면 한다.

  • OS: Windows 7
  • JDK : 1.8.0_162
  • Gradle : 4.5
  • Spring Boot : 2.0.0.RC1
  • IDE: IntelliJ IDEA Community Edition : 2017.3.4
  • pgJDBC: 9.3-1104-jdbc41 (최신 버전은 42.2.1)
  • pgJDBC: 42.2.1
  • PostgreSQL DBMS: 10.1.3

다만 이 해결책은 옛날 pgJDBC를 쓰는 것이라 찜찜하긴 하다.  더불어 왜 pgJDBC 제작자는 최신 버전 구현 시 당당하게 해당 메소드를 구현 안했다고 해 놨을 지도 매우 궁금하다. 최신 pgJDBC 적용하면서 위 문제를 피할 수 있는 방법을 아시는 분의 고견, 언제나 환영한다.

개인적 생각이나, Spring Boot 2.0 정식 버전이 나와도 pgJDBC를 쓰려면 상기 property 추가가 필수적일 듯 하다. 더불어 우아한 방법을 알려주신 김상기님께도 다시 한 번 감사 인사를 드린다.

Happy  Coding!

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중