Home > Mobile >  Liquibase causes "could not prepare statement; SQL" only with H2
Liquibase causes "could not prepare statement; SQL" only with H2

Time:04-28

I integrated Liquibase in my Spring Boot application. Using it with MariaDB works fine.

For unit & integration testing I use a H2 in-memory database. While running tests it causes following exception:

org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select user0_.id as id1_19_0_, user0_.created_at as created_2_19_0_, user0_.updated_at as updated_3_19_0_, user0_.version as version4_19_0_, user0_.activated as activate5_19_0_, user0_.birthday as birthday6_19_0_, user0_.email as email7_19_0_, user0_.firstname as firstnam8_19_0_, user0_.force_password_change as force_pa9_19_0_, user0_.password_hash as passwor10_19_0_, user0_.role as role11_19_0_, user0_.surname as surname12_19_0_ from users user0_ where user0_.id=?]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259) ~[spring-orm-5.3.19.jar:5.3.19]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233) ~[spring-orm-5.3.19.jar:5.3.19]

My prod config (working):

spring:
  main:
    allow-bean-definition-overriding: true
  datasource:
    url: jdbc:mariadb://localhost:3307/testdb
    username: user
    password: psw

  jpa:
    generate-ddl: false
    database-platform: org.hibernate.dialect.MariaDB103Dialect

  sql:
    init:
      mode: never

  liquibase:
    enabled: true
    change-log: classpath:db/db.changelog-master.yaml

My test config (not working):

spring:
  main:
    allow-bean-definition-overriding: true

  datasource:
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;NON_KEYWORDS=user
    username: sa
    driver-class-name: org.h2.Driver
    password: password

  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    generate-ddl: false

  sql:
    init:
      mode: never

  liquibase:
    change-log: classpath:db/db.changelog-master.yaml
    enabled: true

  test:
    database:
      replace: none

What I tried:

  • Multiple url configs including the NON_KEYWORDS option from H2 to exclude problems with user as it is maybe interpreted as a keyword.

As it is working with MariaDB I think it is a problem related to H2.

Thankful for any help, documentation, link whatever :)

CodePudding user response:

You have your h2 url set to this string:

    datasource:
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;NON_KEYWORDS=user
    username: sa
    driver-class-name: org.h2.Driver
    password: password

In the documentation linked here, you can see that they've set that up slightly differently than you have with spring boot and h2:

By default, Spring Boot configures the application to connect to an in-memory store with the username sa and an empty password.

However, we can change those parameters by adding the following properties to the application.properties file:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Since the error references the hibernate URL towards the end, and the only change made was to add the h2 dataset, I searched for spring boot and h2 to find the documentation.

CodePudding user response:

Actually, the problem was with my schema. As H2 does not support some features MariaDB does, it is not starting and therefore jpa is not able to prepare the SQL statement as the tables do not exist.

  • Related