Search code examples
spring-boothibernatejpah2liquibase

New H2 version breaks liquibase


New version of H2 seems to have broken liquibase and JPA

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.h2test</groupId>
    <artifactId>h2test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>h2test</name>
    <description>h2test</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
            <version>4.7.1</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.210</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

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

classes:

package com.h2test.h2test.domain;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String firstName;

    @Column
    private String lastName;
    
}

package com.h2test.h2test.repository;

import com.h2test.h2test.domain.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}

@RestController
public class SomethingController {

    @Autowired
    private PersonRepository personRepository;

    @GetMapping
    public String test() {

        Person person = new Person();
        person.setFirstName("first name");
        person.setLastName("last name");

        personRepository.save(person);
        return "hello";
    }
}

Liquibase file:

databaseChangeLog:
  - changeSet:
      id:  createTable-example
      author:  liquibase-docs
      changes:
        -  createTable:
             tableName:  person
             columns:
               -  column:
                    name:  id
                    type:  int
                    autoIncrement:  true
                    constraints:
                      primaryKey:  true
                      nullable:  false
               -  column:
                    name:  first_name
                    type:  varchar(50)
               -  column:
                    name:  last_name
                    type:  varchar(50)
                    constraints:
                      nullable:  false

When triggering the REST ENDPOINT localhost:8080 that creates and saves the Person entity I get the following error:

org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "ID"; SQL statement: insert into person (id, first_name, last_name) values (null, ?, ?) [23502-202] at org.h2.message.DbException.getJdbcSQLException(DbException.java:508) ~[h2-2.0.202.jar:2.0.202] at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) ~[h2-2.0.202.jar:2.0.202]

This seems to only happen in the newer versions of H2. Any help is appreciated


Solution

  • Version 2.6.3 of spring-boot-starter-data-jpa has org.hibernate:hibernate-core:5.6.4.Final in its dependencies. This version doesn't support H2 2.x.y. You need to use 5.6.5:

    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-core</artifactId>
       <version>5.6.5.Final</version>
    </dependency>
    

    Also something is wrong with your classpath. You have H2 2.1.210 in dependencies, but exception in your question has error code 23502-202, it means it was produced by H2 2.0.202, you shouldn't use this outdated version, Hibernate ORM may have some problems with it.