阅读弹簧开机5的动作,第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.sql
和main/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/jdbc调料entrepository.java):
@Override
public Iterable<Ingredient> findAll() {
return jdbc.query("SELECT id, name, type FROM Ingredient",
this::mapRowToIngredient);
}
我得到了胸里叶错误,因为它无法呈现模板,因为所需的数据不可用,因为没有执行表的schema.sql
。如何使弹簧执行schema.sql
,以便有这些数据可用?
PS: theschema.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
在Spring Boot 2.5中,使用Hibernate时data.sql
和squema.sql
的初始化是不同的。下面是升级指南: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
。请注意,这不是一个好的做法。
您还需要以下属性
spring.jpa.hibernate.ddl-auto=none
你必须仔细阅读文档,你就会明白的。
Spring Boot根据是否为您选择一个默认值;认为您的数据库是嵌入式的(默认创建-删除)或不(默认无)
这意味着对于嵌入的h2数据库,应用的默认属性是spring.jpa.hibernate.ddl-auto=create-drop
因此,即使您提供了脚本,它们也会被hibernate的创建-删除模式初始化所覆盖。这就是为什么你需要手动设置spring.jpa.hibernate.ddl-auto=none
发现问题既不是数据库也不是任何属性设置。问题实际上在视图中。本项目使用thymeleaf
模板,使用form
标签的特殊属性->th:object
。我没有指定哪个对象应该接受从这个表单提交的数据,因此模板引擎转储异常。我认为异常是由H2引起的原因是我没有看到任何初始模式(schema.sql
)及其后续填充(data.sql
)执行的日志语句。所以真正的原因是在视图模板中。
我假设您使用的是最新的Spring Boot版本。
您必须在应用程序中设置以下内容。属性来激活这个特性:
spring.sql.init.mode=always