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?
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
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"));
}
}
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
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
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"));
};
}
}
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:
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
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/
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.
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();
}
}
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.
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:
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)));
};
}
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()));
}
}