web-dev-qa-db-fra.com

Spring Boot - Chargement des données initiales

Je me demande quel est le meilleur moyen de charger les données de la base de données initiale avant le démarrage de l'application? Ce que je recherche, c’est quelque chose qui remplira ma base de données H2 de données.

Par exemple, j'ai un modèle de domaine "Utilisateur". Je peux accéder aux utilisateurs en accédant à/users mais, au départ, il n'y aura aucun utilisateur dans la base de données. Je dois donc les créer. Est-il possible de remplir la base de données automatiquement?

À l'heure actuelle, j'ai un bean qui est instancié par le conteneur et crée des utilisateurs pour moi.

Exemple:

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

Mais je doute fort que ce soit la meilleure façon de le faire. Ou est-ce?

126
Lithicas

Vous pouvez simplement créer un fichier data.sql dans votre src/main/resources et il sera automatiquement exécuté au démarrage. Dans ce fichier, vous ajoutez simplement quelques instructions d'insertion, par exemple:

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

De même, vous pouvez créer un fichier schema.sql (ou schema-h2.sql) pour créer votre schéma:

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

Normalement, vous ne devriez pas avoir à le faire car Spring Boot configure déjà Hibernate pour créer votre schéma en fonction de vos entités pour une base de données en mémoire. Si vous voulez vraiment utiliser schema.sql, vous devrez désactiver cette fonctionnalité en l'ajoutant à votre application.properties:

spring.jpa.hibernate.ddl-auto=none

Plus d'informations peuvent être trouvées dans la documentation sur Initialisation de la base de données .


Si vous utilisez Spring Boot 2 , l’initialisation de la base de données ne fonctionne que pour les bases de données incorporées (H2, HSQLDB, ...). Si vous souhaitez également l'utiliser pour d'autres bases de données, vous devez modifier la propriété spring.datasource.initialization-mode:

spring.datasource.initialization-mode=always

Si vous utilisez plusieurs fournisseurs de base de données, vous pouvez nommer votre fichier data-h2.sql ou data-mysql .sql en fonction de la plate-forme de base de données que vous souhaitez utiliser.

Pour que cela fonctionne, vous devez configurer la propriété spring.datasource.platform bien que:

spring.datasource.platform=h2
197
g00glen00b

Si je veux simplement insérer des données de test simples, j'implémente souvent un ApplicationRunner . Les implémentations de cette interface sont exécutées au démarrage de l’application et peuvent, par exemple, être utilisées. un référentiel auto-câblé pour insérer des données de test.

Je pense qu'une telle implémentation serait légèrement plus explicite que la vôtre car l'interface implique que votre implémentation contienne quelque chose que vous voudriez faire directement après que votre application soit prête.

Votre implémentation aurait l'air qc. comme ça:

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

Comme suggestion essayez ceci:

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

Option 2: Initialiser avec des scripts de schéma et de données

Prérequis: dans application.properties, vous devez mentionner ceci:

spring.jpa.hibernate.ddl-auto=none (sinon les scripts seront ignorés par hibernate et analysera le projet pour les classes @Entity et/ou @Table annotées)

Ensuite, dans votre classe MyApplication, collez ceci:

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

Où le dossier scripts est situé sous le dossier resources (Idée IntelliJ)

J'espère que ça aide quelqu'un

23
Reborn

Vous pouvez ajouter une propriété spring.datasource.data à application.properties répertoriant les fichiers SQL que vous souhaitez exécuter. Comme ça:

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

Les instructions SQL insérer dans chacun de ces fichiers seront ensuite exécutées, vous permettant de garder les choses en ordre

18
robjwilkins

Vous pouvez utiliser quelque chose comme ceci:

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

Spring Boot vous permet d'utiliser un script simple pour initialiser votre base de données, en utilisant Spring Batch .

Néanmoins, si vous souhaitez utiliser quelque chose d'un peu plus élaboré pour gérer les versions de base de données, etc., Spring Boot s'intègre bien avec Flyway .

Voir aussi:

8
Xtreme Biker

Dans Spring Boot 2, data.sql ne fonctionnait pas avec moi comme dans Spring Boot 1.5.

import.sql

De plus, un fichier nommé import.sql à la racine du chemin de classe est exécuté au démarrage si Hibernate crée le schéma à partir de rien (c'est-à-dire si la propriété ddl-auto est définie pour créer ou créer une suppression).

Note très important si vous insérez des clés ne peuvent pas être dupliquées n'utilisez pas ddl-auto La propriété est définie pour se mettre à jour car à chaque redémarrage, les mêmes données seront insérées à nouveau

Pour plus d’informations, visitez le site Web du printemps

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

7
Ismail

Voici comment j'ai eu ça:

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

}

Merci à l'auteur de cet article:

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

5
adkl

Vous pouvez simplement créer un fichier import.sql dans src/main/resources et Hibernate l'exécutera lors de la création du schéma.

4
Francesco Papagno

J'ai résolu le même problème de cette façon:

@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

vous pouvez vous inscrire et écouteur d'événement pour atteindre cet objectif comme ci-dessous:

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

Lorsque ContextRefreshEvent est déclenché, nous avons accès à tous les beans auto-câblés de l'application, y compris les modèles et les référentiels.

1
Ahmed Ahmed

Si quelqu'un a du mal à faire en sorte que cela fonctionne même après le réponse acceptée , pour moi, le travail ne consiste qu'à ajouter dans mon src/test/resources/application.yml le H2 datasource les détails:

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

Cela fonctionnera aussi.

    @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
Udara S.S Liyanage

Le plus compact (pour les données dynamiques) a mis la solution @ mathias-dpunkt dans MainApp (avec Lombok @AllArgsConstructor):

@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