229 votes

Spring Boot - Chargement des données initiales

Je me demande quelle est la meilleure façon de charger les données initiales de la base de données avant le démarrage de l'application ? Ce que je cherche, c'est quelque chose qui va remplir ma base de données H2 avec des données.

Par exemple, j'ai un modèle de domaine "User". Je peux accéder aux utilisateurs en allant dans /users mais, au départ, il n'y aura pas d'utilisateurs dans la base de données et je devrai les créer. Existe-t-il un moyen de remplir automatiquement la base de données avec des données ?

Actuellement, j'ai un Bean qui est instancié par le conteneur et qui 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 procéder. Ou bien l'est-elle ?

4 votes

Cela fonctionnera, ou simplement ajouter data.sql et/ou schema.sql pour initier les données Tout ceci est documenté dans le guide de référence (que je vous conseille de lire).

0 votes

Veuillez cocher la bonne réponse si cela vous a aidé.

0 votes

Quelqu'un a-t-il réussi à le faire fonctionner ? Je n'arrive toujours pas à le mettre en place et je ne sais pas ce qui me manque. git.io/v5SWx

368voto

g00glen00b Points 10383

Vous pouvez créer un données.sql dans votre src/main/ressources et il sera exécuté automatiquement au démarrage. Dans ce fichier, vous pouvez ajouter quelques déclarations 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 schéma.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 puisque Spring boot configure déjà Hibernate pour créer votre schéma basé sur vos entités pour une base de données en mémoire. Si vous voulez vraiment utiliser schema.sql, vous devez désactiver cette fonctionnalité en l'ajoutant à votre application.properties :

spring.jpa.hibernate.ddl-auto=none

Vous trouverez de plus amples informations 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 embarquées (H2, HSQLDB, ...). Si vous souhaitez l'utiliser pour d'autres bases de données également, vous devez modifier l'option spring.datasource.initialization-mode propriété :

spring.datasource.initialization-mode=always

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

Pour que cela fonctionne, vous devez configurer l'interface de l'utilisateur. spring.datasource.platform propriété cependant :

spring.datasource.platform=h2

0 votes

Merci @g00glen00b pour avoir clarifié : "et il sera exécuté automatiquement au démarrage". J'obtenais des erreurs lorsque j'ai inclus le fichier data.sql dans la configuration de mon haricot en utilisant l'option addScript(s). Comme à ce stade, le schéma n'avait pas encore été construit.

0 votes

J'ai un problème avec le séquençage de la création des objets de la BD et l'exécution du data.sql. Le script est exécuté avant la création des entités db. Voici mon post sur le problème : stackoverflow.com/questions/38040572/

0 votes

Il semble que le lien ci-dessus soit incorrect. stackoverflow.com/questions/46066575/ J'ai également créé un exemple de projet mettant en évidence le problème. git.io/v5SWx

98voto

Mathias Dpunkt Points 1427

Si je veux simplement insérer des données de test simples, j'implémente souvent un fichier ApplicationRunner . Les implémentations de cette interface sont exécutées au démarrage de l'application et peuvent utiliser, par exemple, un référentiel auto-connecté 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 contient quelque chose que vous souhaitez faire directement après que votre application soit prête.

Votre mise en œuvre ressemblerait à quelque chose comme ceci :

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

38voto

Reborn Points 934

Il existe de multiples façons d'y parvenir. Je préfère utiliser l'une des options suivantes :

Option 1 : Initialisation avec CommandLineRunner haricot :

@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 : Initialisation avec schéma et données SQL scripts

Conditions préalables :

application.properties

spring.jpa.hibernate.ddl-auto=none

Explication :

Sans ddl-auto Les scripts SQL seront ignorés par Hibernate et déclenchera le comportement par défaut - le balayage du projet pour les @Entity et/ou @Table les classes annotées.

Ensuite, dans votre MyApplication classe coller 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;
}

Donde scripts est situé sous resources dossier (IntelliJ Idea)

J'espère que cela aidera quelqu'un

Mise à jour 04-2021 : Les deux options peuvent être combinées avec Profils de printemps car cela vous permettra d'éviter de créer des fichiers de configuration supplémentaires, ce qui vous facilitera la vie en tant que développeur.

3 votes

L'option 2 est excellente car elle fournit une preuve explicite de ce qui se passe. En cas de sources de données multiples, il peut être nécessaire de désactiver la classe DataSourceAutoConfiguration.class de Spring, auquel cas toutes les autres solutions data.sql et schema.sql fournies ici cessent de fonctionner.

1 votes

Si vous voulez charger les données initiales tout en souhaitant qu'Hibernate crée la DDL, mais que vous disposez de plusieurs sources de données et que vous les configurez manuellement, la meilleure option dans ce cas est de déclarer le bean DataSourceInitializer de Spring comme suit stackoverflow.com/a/23036217/3092830 car il prendra en charge le problème de @PostConstruct pour vous.

0 votes

Spring.jpa.hibernate.ddl-auto=none a réglé mon problème, car mon fichier data.sql était ignoré par JPA jusqu'à ce que je définisse cette propriété. Merci beaucoup.

14voto

Grauzone Points 100

Vous pouvez utiliser quelque chose comme ça :

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

11voto

Xtreme Biker Points 5612

Spring Boot vous permet d'utiliser un simple script pour initialiser votre base de données, à l'aide des éléments suivants Lot de printemps .

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

Voir aussi :

8 votes

Suggérer un lot de printemps ici semble exagéré.

0 votes

@Nick, l'OP ne mentionne pas la quantité de données Quoi qu'il en soit, la réponse ne concerne pas uniquement le lot de printemps.

0 votes

À mon avis, Flyway ou Liquibase est la bonne solution. Je ne suis pas sûr du commentaire de Nick et plus encore des upvotes de /src/main/resources. Oui, ce dernier fonctionnerait pour les petits projets. La réponse de Xtreme Biker donne via un très petit effort beaucoup plus de fonctionnalités.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X