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

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


当前回答

你可以这样使用:

@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 Boot允许您使用一个简单的脚本来初始化数据库,使用Spring Batch。

不过,如果您想使用一些更详细的东西来管理DB版本等等,Spring Boot可以很好地与Flyway集成。

参见:

Spring Boot数据库初始化

您可以使用下面的代码。在下面的代码中,数据库插入发生在spring引导应用程序启动期间。

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

}

如果您来到这里,似乎什么都不适合您,那么您可能受到了Spring Boot 2.5及以后引入的一些更改的影响。

这里是我为postgresql使用的全部属性集。

spring:
  sql.init.mode: always   <-----------------
  datasource:
    url: jdbc:postgresql://localhost:5432/products
    username: 
    password: 
  jpa:
    defer-datasource-initialization: true  <------------------
    hibernate:
      ddl-auto: create-drop   <----------------
    database-platform: org.hibernate.dialect.PostgreSQLDialect

我还用<——标记了当前主题的相关属性,以便实现以下功能。

ORM供应商将从Java实体模型为您创建数据库模式。 创建数据库模式后,初始数据将从data.sql文件加载到数据库中

Ps:不要忘记添加文件的初始数据,数据。src/main/resources下的SQL

同样作为参考:Spring Boot 2.5发行说明

如果你想只插入几行,你有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

     }

我创建了一个库,用于在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包。