Spring启动-加载初始数据

Spring启动-加载初始数据,spring,spring-boot,spring-data,Spring,Spring Boot,Spring Data,我想知道在应用程序启动之前加载初始数据库数据的最佳方法是什么?我要找的是能够用数据填充我的H2数据库的东西 例如,我有一个域模型“User”,我可以通过转到/users访问用户,但最初数据库中没有任何用户,所以我必须创建它们。是否存在自动向数据库填充数据的方法 目前,我有一个Bean,它由容器实例化并为我创建用户 例如: @Component public class DataLoader { private UserRepository userRepository; @A

我想知道在应用程序启动之前加载初始数据库数据的最佳方法是什么?我要找的是能够用数据填充我的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"));
    }
}

但我非常怀疑这是最好的方法。或者是吗?

Spring Boot允许您使用一个简单的脚本来初始化数据库

不过,如果您想使用更精细的东西来管理DB版本等,Spring Boot与

另请参见:


您可以在src/main/resources文件夹中创建一个data.sql文件,并在启动时自动执行。在此文件中,您可以添加一些insert语句,例如:

插入用户(用户名、姓氏、姓氏)值
(‘拉拉’、‘拉拉’、‘拉拉’),
(‘lolo’、‘lolo’、‘lolo’);

同样,您也可以创建一个schema.sql文件(或schema-h2.sql)来创建您的模式:

创建表任务(
id整数主键,
说明VARCHAR(64)不为空,
完成的位不为空);
尽管通常情况下您不应该这样做,因为SpringBoot已经配置Hibernate,以便基于内存中数据库的实体创建模式。如果确实要使用schema.sql,则必须通过将其添加到应用程序中来禁用此功能。属性:

spring.jpa.hibernate.ddl-auto=none
更多信息可在有关的文档中找到


如果您使用的是Spring boot 2,则数据库初始化仅适用于嵌入式数据库(H2、HSQLDB等)。如果还想将其用于其他数据库,则需要更改
spring.datasource.initialization mode
属性:

spring.datasource.initialization-mode=always

如果您使用多个数据库供应商,则可以根据要使用的数据库平台将文件命名为data-h2.sqldata-mysql.sql

要实现这一点,您必须配置
spring.datasource.platform
属性:

spring.datasource.platform=h2

如果我只想插入简单的测试数据,我通常会实现一个。此接口的实现在应用程序启动时运行,可以使用自动连线存储库插入一些测试数据

我认为这样的实现将比您的实现更为明确,因为接口意味着您的实现包含您希望在应用程序准备就绪后直接执行的操作

您的实现将如下所示:

@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"));
    }
}
@SpringBootApplication  
public class Application {

@Autowired
private UserRepository userRepository;

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

@Bean
InitializingBean sendDatabase() {
    return () -> {
        userRepository.save(new User("John"));
        userRepository.save(new User("Rambo"));
      };
   }
}

您只需在
src/main/resources
中创建一个
import.sql
文件,Hibernate将在创建模式时执行它。

实现这一点的方法有多种。我更喜欢使用以下选项之一:

选项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脚本初始化

先决条件:

应用程序属性

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;
}
其中
scripts
文件夹位于
resources
文件夹下(IntelliJ Idea)

希望它能帮助别人


更新04-2021:这两个选项都可以很好地结合使用,因为这将帮助您避免创建额外的配置文件,从而简化开发人员的生活。

您可以使用以下内容:

@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"));
    }
}
@SpringBootApplication  
public class Application {

@Autowired
private UserRepository userRepository;

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

@Bean
InitializingBean sendDatabase() {
    return () -> {
        userRepository.save(new User("John"));
        userRepository.save(new User("Rambo"));
      };
   }
}

您可以将
spring.datasource.data
属性添加到
application.properties
中,列出要运行的sql文件。像这样:

spring.datasource.data=classpath:accounts.sql, classpath:books.sql, classpath:reviews.sql
每个文件中的sql insert语句都将运行,从而使您能够保持整洁

如果将文件放在类路径中,例如在
src/main/resources
中,它们将被应用。或者将
类路径:
替换为
文件:
并使用文件的绝对路径

如果要运行DDL类型的SQL,请使用:

spring.datasource.schema=classpath:create_account_table.sql

编辑:这些解决方案非常有助于您快速启动和运行,但是对于更适合生产的解决方案,值得一看,例如,或。这些框架与spring很好地集成,并提供了一种快速、一致、版本控制的方式来初始化模式和静态数据。

以下是我获得的方法:

@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {

    /**
     * This event is executed as late as conceivably possible to indicate that
     * the application is ready to service requests.
     */

    @Autowired
    private MovieRepositoryImpl movieRepository;

    @Override
    public void onApplicationEvent(final ApplicationReadyEvent event) {
        seedData();
    }

    private void seedData() {
        movieRepository.save(new Movie("Example"));

        // ... add more code
    }

}
@组件
公共类应用程序启动实现ApplicationListener这也会起作用

    @Bean
    CommandLineRunner init (StudentRepo studentRepo){
        return args -> {
            // Adding two students objects
            List<String> names = Arrays.asList("udara", "sampath");
            names.forEach(name -> studentRepo.save(new Student(name)));
        };
    }
@Bean
CommandLineRunner初始化(StudentRepo StudentRepo){
返回参数->{
//添加两个学生对象
列表名称=Arrays.asList(“udara”、“sampath”);
name.forEach(name->studentRepo.save(新学生(姓名));
};
}

您可以通过注册和事件侦听器来实现以下目的:

@EventListener
public void seed(ContextRefreshedEvent event) {
    userRepository.save(new User("lala", "lala", "lala"));
}
当触发ContextRefreshEvent时,我们可以访问应用程序中的所有自动连线bean — 包括模型和存储库。

最紧凑的(用于动态数据)将@mathias dpunkt解决方案放入MainApp(使用Lombok
@AllArgsConstructor
):


如果有人在努力使其工作,即使在以下情况下,对我来说,只需添加我的
src/test/resources/application.yml
H2
datasource
详细信息:

spring:
  datasource:
    platform: h2
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password:

在SpringBoot2中,data.sql与SpringBoot1.5中的data.sql不一样

import.sql

此外,名为

    @SpringBootApplication
        @Slf4j
        public class HospitalManagementApplication {

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

            @Bean
            ApplicationRunner init(PatientRepository repository) {
                return (ApplicationArguments args) ->  dataSetup(repository);
            } 

            public void dataSetup(PatientRepository repository){
            //inserts

     }
@Component
public class DataLoader implements CommandLineRunner {

    private UserRepository userRepository;

    public DataLoader(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public void run(String... args) throws Exception {
         LoadUsers()
    }

    private void LoadUsers() {
        userRepository.save(new User("lala", "lala", "lala"));
    }
}
@SpringBootApplication
public class Application implements CommandLineRunner {
    
    @Autowired
    private IService<Car> service;

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

    @Override
    public void run(String... args) throws Exception {
        for(int i=1; i<=1000; i++) {
            Car car = new Car();
            car.setName("Car Name "+i);
            book.setPrice(50 + i);
            service.saveOrUpdate(car);
        }
    }

}