web-dev-qa-db-fra.com

Spring Boot: Hibernate et Flyway boot order

J'ai créé l'application Spring. Pom xml est joint.

Il a une configuration comme celle-ci (ci-dessous) et un outil de migration db/migration/V1__init.sql pour Flyway db.

Il a une base de données en mémoire hsqldb et il est créé après le démarrage de l'application. Il est propre après sa création.

Je veux qu'Hibernate crée un schéma basé sur des classes d'entités, puis Flyway remplit les tables. Flyway démarre maintenant V1__init.sql avant la création des tables et lève une exception. Comment puis-je modifier cette commande ou quelle solution puis-je faire?

spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HSQLDialect

pom.xml:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.3.RELEASE</version>
    <relativePath/>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <Java.version>1.8</Java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>1.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.11.Final</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>4.2.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring4</artifactId>
        <version>2.1.4.RELEASE</version>
    </dependency>

    <!-- For using 'LEGACYHTML5' mode in Thymeleaf -->
    <dependency>
        <groupId>net.sourceforge.nekohtml</groupId>
        <artifactId>nekohtml</artifactId>
        <version>1.9.21</version>
    </dependency>
    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.4.01</version>
    </dependency>

    <dependency>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>1.3.3.RELEASE</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
18
user3636486

J'ai eu le même problème.

Je voulais que mon schéma soit créé par hibernate en raison de l'indépendance de sa base de données. J'ai déjà eu la peine de trouver un schéma sympa pour mon application dans mes cours jpa, je n'aime pas me répéter.

Mais je veux que l'initialisation des données se fasse de manière versionnée, ce que flyway est bon.

Spring boot exécute des migrations de voie de migration avant la mise en veille prolongée. Pour le changer, j'ai annulé l'initialiseur Spring Boot pour ne rien faire. J'ai ensuite créé un deuxième initialiseur qui s'exécute après la mise en veille prolongée. Il vous suffit d'ajouter cette classe de configuration:

import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

@Configuration
public class MigrationConfiguration {


    /**
     * Override default flyway initializer to do nothing
     */
    @Bean
    FlywayMigrationInitializer flywayInitializer(Flyway flyway) {
        return new FlywayMigrationInitializer(flyway, (f) ->{} );
    }


    /**
     * Create a second flyway initializer to run after jpa has created the schema
     */
    @Bean
    @DependsOn("entityManagerFactory")
    FlywayMigrationInitializer delayedFlywayInitializer(Flyway flyway) {
        return new FlywayMigrationInitializer(flyway, null);
    }


}

Ce code a besoin de Java 8, si vous avez Java 7 ou antérieur, remplacez (f)->{} avec une classe interne qui implémente FlywayMigrationStrategy

Bien sûr, vous pouvez le faire aussi facilement en xml.

Assurez-vous d'ajouter ceci à votre application.properties:

flyway.baselineOnMigrate = true
22
user3707816

La configuration automatique Spring Boot de Flyway garantit que les migrations de base de données ont été exécutées avant l'initialisation d'Hibernate. En d'autres termes, vous ne pouvez pas compter sur la configuration automatique de Flyway et utiliser Flyway pour remplir les tables créées par Hinernate.

Une solution consiste à adopter pleinement Flyway et à l'utiliser à la fois pour créer les tableaux et les remplir. Vous pouvez ensuite désactiver la création de table d'Hibernate (spring.jpa.hibernate.ddl-auto=none). Cette approche est plus robuste car elle permettra à votre base de données d'évoluer plus facilement. C'est ce que je recommanderais de faire.

Une autre solution consiste à désactiver la configuration automatique de Flyway (flyway.enabled=false) et pour le configurer vous-même. Vous pouvez ensuite configurer Flyway pour qu'il dépende d'Hibernate afin qu'Hibernate ait créé les tables avant que Flyway n'essaye de les remplir.

13
Andy Wilkinson

Toutes les migrations SQL commenceront après qu'Hibernate aura créé toutes les tables.

Spring Boot 2.2.2, Flyway 6.0.8

Pour désactiver le démarrage pour Flyway, insérez-le dans resources/application.properties:

spring.flyway.enabled=false

Créez une configuration distincte pour Flyway pour le charger lorsque Hibernate est prêt:

@Configuration
public class FlywayConfiguration {

    @Autowired
    public FlywayConfiguration(DataSource dataSource) {
        Flyway.configure().baselineOnMigrate(true).dataSource(dataSource).load().migrate();
    }
}

Démarrez vos scripts de migration à partir de la version 2:

resources/db.migration/V2__fill-tables.sql

V1 est utilisé comme référence, le fichier V1 sera ignoré.

4
pavelety

Pour les utilisateurs plus récents qui utilisent Spring Boot +2.1 et comme @mota l'a commenté dans la réponse de @ user3707816, vous pouvez utiliser spring.flyway.enabled = false dans application.properties, puis créer une nouvelle instance manuellement:

Flyway.configure().dataSource(dataSource)
                .baselineOnMigrate(true)
                .schemas(PG_DATABASE_SCHEMA)//optional, by default is public
                .load().migrate();
1
peterzinho16

peut être à cause de la commande

ajouter sur application.properties

flyway.out-of-order = true

ou application.yml au printemps

flyway:
  out-of-order: true