H2 not creating/updating table in my Spring Boot app. Something's wrong with my Entity?

Viewed 79682

I want to keep some data in H2 database by making a CRUD repository, using Hibernate.

I can't get the database to store my entries whatsoever. Currently, I'm trying to achieve that during updating the db by making a sample entry. Entry is looking good in the logs, but table is not created/updated/generated.

Why Hibernate is not unable to create a table in this case? (if the problem lies in structure of my data)

Here's my Entity, Game.java class (I've tried without @Column annotations, no difference. Id is not auto-generated, I need to be able to enter my own ID everytime):

@Entity
@Table(name = "GAME")
public class Game {

    @Id
    @Column (name = "ID")
    private long id;

    @Column (name = "NAME")
    private String name;

    @Column(name = "STORYLINE", length = 4000)
    private String storyline;

    @Column(name = "AGGREGATED_RATING")
    @JsonProperty("aggregated_rating")
    private double aggregatedRating;

    @Column(name = "FIRST_RELEASE_DATE")
    @JsonProperty("first_release_date")
    private long firstReleaseDate;

    @Embedded
    private Cover cover;

    public Game(){

    }

    public Game(long id, String name, String storyline, double aggregatedRating, long firstReleaseDate, Cover cover) {
        this.id = id;
        this.name = name;
        this.storyline = storyline;
        this.aggregatedRating = aggregatedRating;
        this.firstReleaseDate = firstReleaseDate;
        this.cover = cover;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getStoryline() {
        return storyline;
    }

    public double getAggregatedRating() {
        return aggregatedRating;
    }

    public long getFirstReleaseDate() {
        return firstReleaseDate;
    }

    public Cover getCover() {
        return cover;
    }


}

And here's Cover.java class:

@Embeddable
public class Cover {

    @Column (name = "URL")
    private String url;
    @JsonProperty("cloudinary_id")
    @Column (name = "CLOUDINARY_ID")
    private String cloudinaryId;
    @Column (name = "WIDTH")
    private Integer width;
    @Column (name = "HEIGHT")
    private Integer height;

    public Cover(){
    }

    public Cover(String url, String cloudinaryId, Integer width, Integer height) {
        this.url = url;
        this.cloudinaryId = cloudinaryId;
        this.width = width;
        this.height = height;
}

    public String getUrl() {
        return url;
    }

    public String getCloudinaryId() {
        return cloudinaryId;
    }

    public Integer getWidth() {
        return width;
    }

    public Integer getHeight() {
        return height;
    }

}

I configured H2 database here, in application.properties file:

spring.h2.console.enabled=true
spring.h2.console.path=/h2_console
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Repository is configured like this:

import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface GameRepository extends CrudRepository<Game, Long> {
    List<Game> findAllByName(String name);
}

I test my repository by going under localhost:8080/test, where a sample entry should be inserted into table:

@RequestMapping("/test")
public String saveSth(){
    gameRepository.save(new Game(127, "Assassin's Creed II", "The lineage continues as this new chapter introduces Ezio, inheritor of the talents and creed of the Assassins. His family murdered by rival families, Ezio resolves to learn the ancient art of the Assassin in order to seek revenge. He will not do so alone though, allying with historical figures such as philosopher and writer Niccolò Machiavelli. You will also be able to master the art of the assassin with all new weapons and instruments created by the renowned inventor and genius of the Renaissance, Leonardo Da Vinci himself.", 90.25, 1258416000000L, new Cover("//images.igdb.com/igdb/image/upload/t_thumb/doczeiofd1ckpapdhqs7.jpg", "doczeiofd1ckpapdhqs7", 1000, 1426)));
    return "success";
}

I get the following log:

2017-07-25 13:09:58.873 DEBUG 9442 --- [nio-8080-exec-1] org.hibernate.SQL                        : select game0_.id as id1_0_0_, game0_.aggregated_rating as aggregat2_0_0_, game0_.cloudinary_id as cloudina3_0_0_, game0_.height as height4_0_0_, game0_.url as url5_0_0_, game0_.width as width6_0_0_, game0_.first_release_date as first_re7_0_0_, game0_.name as name8_0_0_, game0_.storyline as storylin9_0_0_ from game game0_ where game0_.id=?
Hibernate: select game0_.id as id1_0_0_, game0_.aggregated_rating as aggregat2_0_0_, game0_.cloudinary_id as cloudina3_0_0_, game0_.height as height4_0_0_, game0_.url as url5_0_0_, game0_.width as width6_0_0_, game0_.first_release_date as first_re7_0_0_, game0_.name as name8_0_0_, game0_.storyline as storylin9_0_0_ from game game0_ where game0_.id=?
2017-07-25 13:09:58.875 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [127]
2017-07-25 13:09:58.894 DEBUG 9442 --- [nio-8080-exec-1] org.hibernate.SQL                        : insert into game (aggregated_rating, cloudinary_id, height, url, width, first_release_date, name, storyline, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into game (aggregated_rating, cloudinary_id, height, url, width, first_release_date, name, storyline, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
2017-07-25 13:09:58.895 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [DOUBLE] - [90.25]
2017-07-25 13:09:58.896 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [doczeiofd1ckpapdhqs7]
2017-07-25 13:09:58.896 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [INTEGER] - [1426]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [VARCHAR] - [//images.igdb.com/igdb/image/upload/t_thumb/doczeiofd1ckpapdhqs7.jpg]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [5] as [INTEGER] - [1000]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [6] as [BIGINT] - [1258416000000]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [7] as [VARCHAR] - [Assassin's Creed II]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [8] as [VARCHAR] - [The lineage continues as this new chapter introduces Ezio, inheritor of the talents and creed of the Assassins. His family murdered by rival families, Ezio resolves to learn the ancient art of the Assassin in order to seek revenge. He will not do so alone though, allying with historical figures such as philosopher and writer Niccolò Machiavelli. You will also be able to master the art of the assassin with all new weapons and instruments created by the renowned inventor and genius of the Renaissance, Leonardo Da Vinci himself.]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [9] as [BIGINT] - [127]

It looks like data is binded to parameters, but in H2 console SELECT * FROM GAME returns me: SELECT * FROM GAME; Table "GAME" not found; SQL statement: SELECT * FROM GAME [42102-193] 42S02/42102 (Help)

I've tried other H2 modes such as create-drop or create, but no success. What worries me is that, I can't even get the database to create an empty table with the correct rows, ready for entries.

I think that something's wrong either with my Entity or missing from my GameRepository configuration, but I have no more ideas to fix this error.

I want to achieve what's here: http://javasampleapproach.com/spring-framework/spring-boot/integrate-h2-database-springboot-spring-jpa-embedded-mode And here: http://www.simplecodestuffs.com/value-object-entity-object-in-hibernate-mapping/

Also, I've tried this set of tutorials for a change: https://springframework.guru/using-the-h2-database-console-in-spring-boot-with-spring-security/ https://springframework.guru/spring-boot-web-application-part-3-spring-data-jpa/

But no luck so far.

10 Answers

Just go to the H2 console for example at: http://localhost:9090/h2-console/ and In the JDBC URL field, type jdbc:h2:mem:testdb to configure the connection to the testdb database in RAM.

Putting this line: spring.jpa.hibernate.ddl-auto = update in your application.properties file start population data in in-memory database and in file based database for H2 data-base.Hope this helps anyone.

Check if you main class(Spring boot application class) is able to scan the entities defined. This usually happens when the entities are in a different package than that of the main class.

use @EntityScan("com.db.jpasample.entity")

@SpringBootApplication
@EntityScan("com.db.jpasample.entity")
public class GsoftApplication {

  public static void main(String[] args) {
    SpringApplication.run(GsoftApplication.class, args);
  }

}

application.properties

server.port = 9090
spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:socialdb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto = create

In the application.properties file, try to use spring.jpa.defer-datasource-initialization=true.

Same problem i faced and i added below changes to resolve it,

i added below version for H2 dependencies in pom.xml

    <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.193</version>
    </dependency>

And added below configuration in application.properties file

spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.driverClassName = org.h2.Driver
spring.datasource.url=jdbc:h2:file:~/test;
spring.datasource.username=sa
spring.datasource.password=

The DataSource Initialization feature for SQL Script has been redesigned in Spring Boot 2.5.


By default, data.sql scripts are now run before Hibernate is initialized. This aligns the behavior of basic script-based initialization with that of Flyway and Liquibase. If you want to use data.sql to populate a schema created by Hibernate, set spring.jpa.defer-datasource-initialization to true. While mixing database initialization technologies is not recommended, this will also allow you to use a schema.sql script to build upon a Hibernate-created schema before it’s populated via data.sql.

Reference:

Spring Boot 2.5 Release Notes

Missing ddl script

i was also facing the same but it seemed i didnt added the ddl part

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:~/test
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=   //empty as i didnt has password in h2
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto = create //add this to create table first time then use 'update'

It should work with your in-memory instance of H2 if you load the data and call all operations within the same JVM session.

It has a lot to do with the design of the connection.

Please check both these:

  • the url to setup the connection
  • the validation and export of schema DDL to the database with the good choice of the parameter of hibernate.hbm2ddl.auto

One has to act on these two parameters, it could require some time.

More options for in memory db.

Related