我想知道在应用程序启动之前加载初始数据库数据的最佳方法是什么?我要找的是一些东西,将填补我的H2数据库与数据。
例如,我有一个域模型“User”,我可以通过访问/users访问用户,但最初在数据库中不会有任何用户,所以我必须创建它们。有没有办法自动用数据填充数据库?
目前,我有一个Bean,它由容器实例化并为我创建用户。
例子:
@Component
public class DataLoader {
private UserRepository userRepository;
@Autowired
public DataLoader(UserRepository userRepository) {
this.userRepository = userRepository;
LoadUsers();
}
private void LoadUsers() {
userRepository.save(new User("lala", "lala", "lala"));
}
}
但我非常怀疑这是不是最好的办法。真的是这样吗?
有多种方法可以实现这一点。我倾向于使用以下选项之一:
选项1:使用CommandLineRunner bean初始化:
@Bean
public CommandLineRunner loadData(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
// fetch all customers
log.info("Customers found with findAll():");
log.info("-------------------------------");
for (Customer customer : repository.findAll()) {
log.info(customer.toString());
}
log.info("");
// fetch an individual customer by ID
Customer customer = repository.findOne(1L);
log.info("Customer found with findOne(1L):");
log.info("--------------------------------");
log.info(customer.toString());
log.info("");
// fetch customers by last name
log.info("Customer found with findByLastNameStartsWithIgnoreCase('Bauer'):");
log.info("--------------------------------------------");
for (Customer bauer : repository
.findByLastNameStartsWithIgnoreCase("Bauer")) {
log.info(bauer.toString());
}
log.info("");
}
}
选项2:使用模式和数据SQL脚本进行初始化
先决条件:
application.properties
spring.jpa.hibernate.ddl-auto=none
解释:
没有ddl-auto SQL脚本将被忽略
休眠和触发默认行为-扫描项目
@实体和/或@表注释类。
然后,在你的MyApplication类中粘贴这个:
@Bean(name = "dataSource")
public DriverManagerDataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:~/myDB;MV_STORE=false");
dataSource.setUsername("sa");
dataSource.setPassword("");
// schema init
Resource initSchema = new ClassPathResource("scripts/schema-h2.sql");
Resource initData = new ClassPathResource("scripts/data-h2.sql");
DatabasePopulator databasePopulator = new ResourceDatabasePopulator(initSchema, initData);
DatabasePopulatorUtils.execute(databasePopulator, dataSource);
return dataSource;
}
脚本文件夹位于资源文件夹下(IntelliJ Idea)
希望它能帮助到别人
更新04-2021:这两个选项都很适合与Spring Profiles结合使用,因为这将帮助您避免创建额外的配置文件,使您作为开发人员的生活变得轻松。
如果我只想插入简单的测试数据,我通常实现一个ApplicationRunner。这个接口的实现在应用程序启动时运行,可以使用自动连接的存储库来插入一些测试数据。
我认为这样的实现会比您的实现稍微明确一些,因为接口暗示您的实现包含一些您希望在应用程序准备好之后直接执行的操作。
你的实现看起来像这样:
@Component
public class DataLoader implements ApplicationRunner {
private UserRepository userRepository;
@Autowired
public DataLoader(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void run(ApplicationArguments args) {
userRepository.save(new User("lala", "lala", "lala"));
}
}
您可以创建一个数据。在src/main/resources文件夹中的SQL文件,它将在启动时自动执行。在这个文件中,你可以添加一些插入语句,例如:
INSERT INTO users (username, firstname, lastname) VALUES
('lala', 'lala', 'lala'),
('lolo', 'lolo', 'lolo');
类似地,您可以创建一个模式。SQL文件(或schema-h2. SQL)来创建你的模式:
CREATE TABLE task (
id INTEGER PRIMARY KEY,
description VARCHAR(64) NOT NULL,
completed BIT NOT NULL);
虽然通常情况下你不需要这样做,因为Spring引导已经配置Hibernate来基于你的实体为内存数据库创建模式。如果你真的想使用模式。SQL,你必须禁用这个功能添加到你的application.properties:
spring.jpa.hibernate.ddl-auto=none
更多信息可以在关于数据库初始化的文档中找到。
如果使用Spring Boot 2,数据库初始化只适用于嵌入式数据库(H2, HSQLDB,…)。如果你想在其他数据库中使用它,你需要改变初始化模式属性:
spring.sql.init.mode=always # Spring Boot >=v2.5.0
spring.datasource.initialization-mode=always # Spring Boot <v2.5.0
如果使用多个数据库供应商,可以将文件命名为data-h2。SQL或data-mysql。SQL,这取决于您想使用的数据库平台。
要做到这一点,你必须配置数据源平台属性:
spring.sql.init.platform=h2 # Spring Boot >=v2.5.0
spring.datasource.platform=h2 # Spring Boot <v2.5.0