【问题标题】:how to initialize H2 database in spring boot如何在spring boot中初始化H2数据库
【发布时间】:2021-10-06 14:47:50
【问题描述】:

阅读spring boot 5 in action,第3章->使用H2数据库,项目结构:

.
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── tacocloud
│   │   │               ├── controllers
│   │   │               │   ├── DesignTacoController.java
│   │   │               │   └── OrderController.java
│   │   │               ├── models
│   │   │               │   ├── Ingredient.java
│   │   │               │   ├── Order.java
│   │   │               │   └── Taco.java
│   │   │               ├── repositories
│   │   │               │   ├── interfaces
│   │   │               │   │   └── IngredientRepository.java
│   │   │               │   └── JdbcIngredientRepository.java
│   │   │               ├── TacoCloudApplication.java
│   │   │               └── WebConfig.java
│   │   └── resources
│   │       ├── application.properties
│   │       ├── data.sql
│   │       ├── schema.sql
│   │       ├── static
│   │       │   ├── images
│   │       │   │   └── TacoCloud.png
│   │       │   └── style.css
│   │       └── templates
│   │           ├── design.html
│   │           ├── home.html
│   │           └── orderForm.html
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── tacocloud
│                       └── TacoCloudApplicationTests.java
└── taco-cloud.iml

当我用maven插件mvn spring-boot:run启动项目时:

2021-07-31 12:41:30.065  INFO 4910 --- [           main] c.e.tacocloud.TacoCloudApplication       : Starting TacoCloudApplication using Java 11.0.11 on Shepherd with PID 4910 (/home/shepherd/Desktop/spring/taco-cloud/target/classes started by shepherd in /home/shepherd/Desktop/spring/taco-cloud)
2021-07-31 12:41:30.067  INFO 4910 --- [           main] c.e.tacocloud.TacoCloudApplication       : No active profile set, falling back to default profiles: default
2021-07-31 12:41:31.195  INFO 4910 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-07-31 12:41:31.205  INFO 4910 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-07-31 12:41:31.206  INFO 4910 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.50]
2021-07-31 12:41:31.281  INFO 4910 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-07-31 12:41:31.281  INFO 4910 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1163 ms
2021-07-31 12:41:31.371  INFO 4910 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-07-31 12:41:31.474  INFO 4910 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2021-07-31 12:41:31.999  INFO 4910 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-07-31 12:41:32.013  INFO 4910 --- [           main] c.e.tacocloud.TacoCloudApplication       : Started TacoCloudApplication in 2.413 seconds (JVM running for 2.812)

我可以看到没有 sql 执行,因此没有创建来自 main/resources/schema.sqlmain/resources/data.sql 的初始表。 (即使 sql 文件根据文档位于正确的目录中)。

所以当我尝试从/design (main/java/com/example/tacocloud/controllers/DesignController.java) 获取此页面时:

@GetMapping
    public String showDesignForm(Model model){
        List<Ingredient> ingredients = new ArrayList<>();
        ingredientRepo.findAll().forEach(ingredients::add);

        Type[] types = Ingredient.Type.values();
        for(Type type: types){
            model.addAttribute(type.toString().toLowerCase(),
                    filterByType(ingredients, type));
        }

        return "design";
    }

调用存储库函数findAll()(main/java/com/example/tacocloud/repositories/JdbcIngredientRepository.java):

 @Override
    public Iterable<Ingredient> findAll() {
        return jdbc.query("SELECT id, name, type FROM Ingredient",
                this::mapRowToIngredient);
    }

我收到 thymeleaf 错误,因为它无法呈现模板,因为所需的数据不可用,因为带有表的 schema.sql 未执行。如何让 spring 执行schema.sql 以使这些数据可用?

PS:schema.sql

create table if not exists Ingredient (
    id varchar(4) not null,
    name varchar(25) not null,
    type varchar(10) not null
);

create table if not exists Taco (
    id identity,
    name varchar(50) not null,
    createdAt timestamp not null
);

create table if not exists Taco_Ingredients(
    taco bigint not null,
    ingredient varchar(4) not null
);

alter table Taco_Ingredients
    add foreign key (taco) references Taco(id);
alter table Taco_Ingredients
    add foreign key (ingredient) references Ingredient(id);

create table if not exists Taco_Order (
    id identity,
    deliveryName varchar(50) not null,
    deliveryStreet varchar(50) not null,
    deliveryCity varchar(50) not null,
    deliveryState varchar(2) not null,
    deliveryZip varchar(10) not null,
    ccNumber varchar(16) not null,
    ccExpiration varchar(5) not null,
    ccCVV varchar(3) not null,
    placedAt timestamp not null
);

create table if not exists Taco_Order_Tacos(
    tacoOrder bigint not null,
    taco bigint not null
);

alter table Taco_Order_Tacos
    add foreign key (tacoOrder) references Taco_Order(id);
alter table Taco_Order_Tacos
    add foreign key (taco) references Taco(id);

application.properties

spring.thymeleaf.cache=false
spring.sql.init.mode=always`

PSS: git 回购: https://github.com/tacocloud/taco-cloud

【问题讨论】:

  • 请包含您的application.properties 文件的内容。
  • 请在 github 或类似网站上创建一个完整的工作项目,以便有人可以查看它...
  • @khmarbaise 查看编辑

标签: java spring spring-boot maven h2


【解决方案1】:

在 Spring Boot 2.5 中,data.sqlsquema.sql 在使用 Hibernate 时的初始化是不同的。这是升级指南:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes#upgrading-from-spring-boot-24

TLDR 是 data.sql 现在在 Hibernate 初始化之前运行。如果您想使用 data.sql 填充 Hibernate 创建的模式,请在属性文件中将 spring.jpa.defer-datasource-initialization 设置为 true。请注意,这不是一个好的做法。

【讨论】:

  • 即使在application.properties 中将该选项设置为 true 也无济于事(即 sql 数据仍未执行且 H2 未填充)
  • 你有一个错字spring.sql.init.mode=always`
【解决方案2】:

你还需要以下属性

spring.jpa.hibernate.ddl-auto=none

你必须仔细阅读documentation,你就会明白。

Spring Boot 会根据它是否认为您的数据库是嵌入式的(默认 create-drop)(默认无)为您选择一个默认值

这意味着对于嵌入式 h2 数据库,应用的默认属性是 spring.jpa.hibernate.ddl-auto=create-drop

因此,即使您提供脚本,它们也会被 hibernate create-drop 架构初始化覆盖。这就是为什么你需要手动设置spring.jpa.hibernate.ddl-auto=none

【讨论】:

    【解决方案3】:

    发现问题既不是数据库也不是任何属性集。问题实际上在视图中。该项目使用thymeleaf 模板,它使用form 标签的特殊属性-> th:object。我没有指定哪个对象应该接受从这个表单提交的数据,因此模板引擎转储异常。我认为异常是由 H2 引起的原因是我没有看到任何执行初始模式 (schema.sql) 及其后续填充 (data.sql) 的日志语句。所以真正的原因在于视图模板。

    【讨论】:

      【解决方案4】:

      我假设您使用的是最新的 Spring Boot 版本。

      您必须在 application.properties 中设置以下内容才能激活此功能:

      spring.sql.init.mode=always
      

      【讨论】:

        猜你喜欢
        • 2018-03-22
        • 2018-09-05
        • 1970-01-01
        • 2018-02-14
        • 2021-11-30
        • 2017-07-29
        • 2018-04-16
        • 2022-01-18
        • 2017-06-10
        相关资源
        最近更新 更多