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

但我非常怀疑这是不是最好的办法。真的是这样吗?


当前回答

如果你想快速插入一些查询,你可以使用h2数据。还有SQL查询

应用程序。属性包括:

spring.jpa.show-sql=true
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb

#This directs the data.sql file and help it to run
spring.sql.init.data-locations=classpath:data.sql
spring.jpa.defer-datasource-initialization=true

数据。SQL文件包括:

INSERT INTO todo (id, username, description, target_date, is_done) VALUES (10001, 'lighteducation', 'Learn dance', CURRENT_DATE ,false);

INSERT INTO todo (id, username, description, target_date, is_done) VALUES (10002, 'lighteducation', 'Learn Angular14', CURRENT_DATE, false);

INSERT INTO todo (id, username, description, target_date, is_done) VALUES (10003, 'lighteducation', 'Learn Microservices', CURRENT_DATE,false);

注:数据。SQL文件应该在src/main/resources中

你的@实体包含

@Getter
@Setter
@AllArgsConstructor
@ToString
@Entity
public class Todo {
    @Id
    @GeneratedValue
    private Long id;

    private String username;
    private String description;
    private Date targetDate;
    private boolean isDone;

    protected Todo() {

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Todo todo = (Todo) o;
        return id == todo.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

基本上就是这样。它将在内存中,这意味着当您重新启动应用程序时,数据将再次与查询显示的相同。

但它很容易进行快速检查

此外,您可以通过http://localhost:8080/h2-console/访问该路径,也可以从.properties文件编辑该路径

其他回答

如果你想只插入几行,你有JPA设置。您可以使用下面的方法

    @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

     }

您可以简单地创建一个导入。在src/main/resources中创建一个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脚本进行初始化

先决条件:

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结合使用,因为这将帮助您避免创建额外的配置文件,使您作为开发人员的生活变得轻松。

这也是可行的。

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

我创建了一个库,用于在Spring Boot应用程序中加载初始/演示数据。你可以在https://github.com/piotrpolak/spring-boot-data-fixtures上找到它

一旦数据fixture启动器位于类路径上,它将在应用程序启动时自动尝试加载DICTIONARY数据(此行为可以由属性控制)—您所需要做的就是注册一个实现DataFixture的bean。

我发现通过代码加载初始数据优于使用SQL脚本加载:

fixture的逻辑与应用程序逻辑/领域模型非常接近,随着领域的发展,它也会进行重构 你可以从增量的演示数据更新中获益——想象一个QA环境中有一些用户数据(在应用程序部署后不需要丢失),但同时你想为你开发的新功能添加数据

数据夹具示例:

/**
 * You can have as many fixture classes as you want.
 * @Order annotation is respected for the fixtures belonging to the same set.
 * You can make your demo database to be incrementally updated with fresh data
 * each time the application is redeployed - all you need to do is to write
 * a good condition in `canBeLoaded()` method.
 */
@Component
public class InitialDataFixture implements DataFixture {

    private final LanguageRepository languageRepository;

    // ...

    @Override
    public DataFixtureSet getSet() {
      return DataFixtureSet.DICTIONARY;
    }

    /**
     * We want to make sure the fixture is applied once and once only.
     * A more sophisticated condition can be used to create incremental demo data
     * over time without the need to reset the QA database (for example).
     */
    @Override
    public boolean canBeLoaded() {
      return languageRepository.size() == 0;
    }

    /**
     * The actual application of the fixture.
     * Assuming that data fixtures are registered as beans, this method can call
     * other services and/or repositories.
     */
    @Override
    public void load() {
      languageRepository.saveAll(Arrays.asList(
          new Language("en-US"), new Language("pl-PL")));
    }
}

这个概念的灵感来自Symfony Doctrine数据fixture包。