web-dev-qa-db-ja.com

Spring Boot - 初期データのロード

アプリケーションが起動する前に初期データベースデータをロードするための最良の方法は何だろうか。私が探しているものは私の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"));
    }
}

しかし、それが最善の方法だと私は非常に疑問に思います。またはそれは?

109
Lithicas

src/main/resources に、単純に data.sql ファイル(またはH2がデータベースの場合にのみ適用する場合はdata-h2.sql)を作成できます。フォルダとそれは起動時に自動的に実行されます。このファイルにいくつかのinsertステートメントを追加するだけです。

INSERT INTO users (username, firstname, lastname) VALUES
  ('lala', 'lala', 'lala'),
  ('lolo', 'lolo', 'lolo');

同様に、 schema.sql ファイル(またはschema-h2.sql)を作成してスキーマを作成できます。

CREATE TABLE task (
  id          INTEGER PRIMARY KEY,
  description VARCHAR(64) NOT NULL,
  completed   BIT NOT NULL);

Springブートは既にインメモリデータベースのためにあなたのエンティティに基づいてあなたのスキーマを作成するためにHibernateを設定しているので、通常あなたはこれをする必要はないはずです。本当にschema.sqlを使いたいのなら、application.propertiesにこれを追加してこの機能を無効にする必要があります。

spring.jpa.hibernate.ddl-auto=none

データベースの初期化 に関するドキュメントでより多くの情報を見つけることができます。


Spring boot 2 を使用している場合、データベースの初期化は埋め込みデータベース(H2、HSQLDBなど)に対してのみ機能します。他のデータベースにも使用したい場合は、spring.datasource.initialization-modeプロパティを変更する必要があります。

spring.datasource.initialization-mode=always
177
g00glen00b

単純なテストデータを挿入したいだけの場合は、 ApplicationRunner を実装することがよくあります。このインタフェースの実装はアプリケーションの起動時に実行され、たとえば次のものを使用できます。テストデータを挿入するためのautowiredリポジトリ.

私は、そのような実装はあなたのものよりわずかに明白であると思います。なぜならインターフェースはあなたの実装があなたがあなたのアプリケーションの準備ができた直後にあなたがやりたい何かを含んでいることを意味します。

あなたの実装は気が遠くなるでしょう。このような:

@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"));
    }
}
57
Mathias Dpunkt

提案としてこれを試してください:

@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: スキーマとデータスクリプトで初期化

前提条件:application.propertiesでは、これに言及する必要があります:

spring.jpa.hibernate.ddl-auto=none(それ以外の場合、スクリプトはHibernateによって無視され、@Entityおよび/または@Tableアノテーション付きクラスについてプロジェクトをスキャンします)

次に、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)

誰かに役立つことを願っています

21
Reborn

実行したいSQLファイルをリストするspring.datasource.dataプロパティをapplication.propertiesに追加することができます。このような:

spring.datasource.data=classpath:accounts.sql, classpath:books.sql, classpath:reviews.sql

これらの各ファイルのsql insertステートメントが実行されるので、物事を整理することができます。

12
robjwilkins

あなたはこのようなものを使うことができます:

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

Spring Bootでは、 Spring Batch を使用して、簡単なスクリプトを使用してデータベースを初期化できます。

それでも、DBバージョンなどを管理するためにもう少し複雑なものを使用したい場合、Spring Bootは Flyway とうまく統合されます。

以下も参照してください。

7
Xtreme Biker

Spring Boot 2では、data.sqlがSpring Boot 1.5のように動作しませんでした

import.sql

さらに、クラスパスのルートにあるimport.sqlという名前のファイルは、Hibernateが最初からスキーマを作成した場合(つまり、ddl-autoプロパティがcreateまたはcreate-dropに設定されている場合)に起動時に実行されます。

キーを複製できない場合に非常に重要な注意ddl-autoプロパティを使用しないでください。再起動するたびに同じデータが再度挿入されるためです。

より多くの情報のためにあなたは春のウェブサイトを眺める

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html

6
Ismail

これが私のやり方です。

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

}

この記事の著者に感謝します。

http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/ /

5
adkl

import.sqlsrc/main/resourcesファイルを作成するだけで、スキーマの作成時にHibernateがそれを実行します。

4

私はこのようにして同様の問題を解決しました:

@Component
public class DataLoader {

    @Autowired
    private UserRepository userRepository;

    //method invoked during the startup
    @PostConstruct
    public void loadData() {
        userRepository.save(new User("user"));
    }

    //method invoked during the shutdown
    @PreDestroy
    public void removeData() {
        userRepository.deleteAll();
    }
}
2
A-Bag

あなたは以下のようにそれを達成するために登録してイベントリスナーを作ることができます:

@EventListener
public void seed(ContextRefreshedEvent event) {
    userRepository.save(new User("lala", "lala", "lala"));
}

ContextRefreshEventが起動されると、モデルとリポジトリを含む、アプリケーション内のすべての自動生成されたBeanにアクセスできます。

1
Ahmed Ahmed

誰かが 受け入れられた答え に従ってもこれを動作させることに苦労しているなら、私のためだけに私の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:
1
Dherik

これもうまくいきます。

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

最もコンパクトな(動的データ用)の@ mathias-dpunktソリューションを(Lombok @AllArgsConstructorを使って)MainAppに入れます。

@SpringBootApplication
@AllArgsConstructor
public class RestaurantVotingApplication implements ApplicationRunner {
  private final VoteRepository voteRepository;
  private final UserRepository userRepository;

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

  @Override
  public void run(ApplicationArguments args) {
    voteRepository.save(new Vote(userRepository.getOne(1), LocalDate.now(), LocalTime.now()));
  }
}
0
GKislin