H2 未在我的 Spring Boot 应用程序中创建/更新表。我的实体有问题吗?

新手上路,请多包涵

我想通过使用 Hibernate 创建一个 CRUD 存储库来将一些数据保存在 H2 数据库中。

我无法让数据库存储我的条目。目前,我正在尝试通过创建示例条目在更新数据库期间实现这一点。条目在日志中看起来不错,但未创建/更新/生成表。

为什么Hibernate在这种情况下不是不能建表呢? (如果问题出在我的数据结构上)

这是我的实体, Game.java 类(我试过没有@Column 注释,没有区别。ID 不是自动生成的,我每次都需要能够输入自己的 ID):

 @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;
    }

}

这是 Cover.java 类:

 @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;
    }

}

我在这里配置了 H2 数据库,在 application.properties 文件中:

 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

存储库 配置如下:

 import org.springframework.data.repository.CrudRepository;

import java.util.List;

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

我通过在 localhost:8080/test 下测试我的存储库,其中应将示例条目插入到表中:

 @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";
}

我得到以下日志:

 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]

看起来数据已绑定到参数,但在 H2 控制台中, SELECT * FROM GAME 返回我:SELECT * FROM GAME;未找到表“GAME”; SQL语句:SELECT * FROM GAME [42102-193] 42S02/42102(求助)

我尝试过其他 H2 模式,例如 create-drop 或 create,但没有成功。让我担心的是,我什至无法让数据库创建一个包含正确行的空表,为条目做好准备。

我认为我的实体有问题或我的 GameRepository 配置中缺少,但我没有更多的想法来修复此错误。

我想实现这里的目标:http: //javasampleapproach.com/spring-framework/spring-boot/integrate-h2-database-springboot-spring-jpa-embedded-mode 在这里: http ://www.simplecodestuffs.com /value-object-entity-object-in-hibernate-mapping/

此外,我尝试了这组教程进行更改: https ://springframework.guru/using-the-h2-database-console-in-spring-boot-with-spring-security/ https://springframework。大师/spring-boot-web-application-part-3-spring-data-jpa/

但到目前为止还没有运气。

原文由 VapeKop 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

看起来数据已绑定到参数,但在 H2 控制台中,SELECT * FROM GAME 没有返回任何内容。该表不存在。

您正在使用 H2 的 in-memory 实例:

 spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

在这种模式下,您无法从启动了 in-memory 数据库的另一个客户端看到更改的内容。

要查看来自其他客户端的更改,您必须使用 TCP 模式。

你有两个解决方案:

  • 使用文件来持久化 H2 的实例。

数据库文件存储在哪里?

当使用像 jdbc:h2:~/test 这样的数据库 URL 时,数据库存储在用户目录中。对于 Windows,这通常是 C:\Documents and Settings\ 或 C:\Users\。如果未设置基本目录(如在 jdbc:h2:./test 中),则数据库文件存储在应用程序启动的目录(当前工作目录)中。从开始菜单使用 H2 控制台应用程序时,这是 /bin。基本目录可以在数据库 URL 中设置。可以使用固定路径或相对路径。当使用 URL jdbc:h2:file:./data/sample 时,数据库存储在目录数据中(相对于当前工作目录)。如果该目录尚不存在,则会自动创建该目录。也可以使用完全限定的目录名称(对于 Windows,驱动器名称)。示例:jdbc:h2:file:C:/data/test

  • 继续使用内存实例,但使用 TCP 模式。

代替 :

 spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

经过 :

 spring.datasource.url=jdbc:h2:tcp://localhost/~/test

通常,当我真的想知道哪个被插入数据库时,我会在 JPA 实体单元测试期间切换到这种模式。

来自 官方文档

内存数据库

对于某些用例(例如:快速原型制作、测试、高性能操作、只读数据库),可能不需要持久化数据,或持久化对数据的更改。该数据库支持内存模式,数据不持久化。 …

在某些情况下,只需要一个到内存数据库的连接。这意味着要打开的数据库是私有的。在这种情况下,数据库 URL 是 jdbc:h2:mem:在同一个虚拟机中打开两个连接意味着打开两个不同的(私有)数据库。

有时需要多个连接到同一个内存数据库。在这种情况下,数据库 URL 必须包含一个名称。示例:jdbc:h2:mem:db1。使用此 URL 访问同一个数据库只适用于同一个虚拟机和类加载器环境。

要从另一个进程或从另一台计算机访问内存数据库,您需要在创建内存数据库的同一进程中启动 TCP 服务器。然后其他进程需要通过 TCP/IP 或 TLS 访问数据库,使用数据库 URL,例如:jdbc:h2:tcp://localhost/mem:db1。


独立 H2 控制台的替代方案:使用可从 Spring Boot 应用程序访问的 H2 控制台

实际上,H2 数据库提供了一个基于浏览器的控制台, Spring Boot 可以为您自动配置 该控制台。当满足这些条件时,控制台会自动配置:

  • 您正在开发基于 servlet 的 Web 应用程序。
  • com.h2database:h2 在类路径上。
  • 您正在使用 Spring Boot 的开发人员工具。

所以这意味着只能在开发中访问。一般你想要什么。

默认情况下,控制台位于 /h2-console

设置 spring.h2.console.path 属性来改变它。

原文由 davidxxx 发布,翻译遵循 CC BY-SA 4.0 许可协议

只需转到 H2 控制台,例如: http://localhost:9090/h2-console/ 并在 JDBC URL 字段中,键入 jdbc:h2:mem:testdb 以配置与 RAM 中的 testdb 数据库的连接。

原文由 Dev M 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题