web-dev-qa-db-fra.com

Réinitialiser périodiquement la base de données Embedded H2

Je configure une nouvelle version de mon application sur un serveur de démonstration et j'aimerais trouver un moyen de réinitialiser la base de données quotidiennement. Je suppose que je peux toujours avoir un travail cron exécutant drop et créer des requêtes mais je recherche une approche plus propre. J'ai essayé d'utiliser une unité de persistance spéciale avec une approche drop-create, mais cela ne fonctionne pas car le système se connecte et se déconnecte fréquemment du serveur (à la demande).

Est-ce qu'il y a une meilleure approche?

38
javydreamercsw

H2 prend en charge une instruction SQL spéciale pour supprimer tous les objets :

DROP ALL OBJECTS [DELETE FILES]

Si vous ne voulez pas supprimer toutes les tables, vous pouvez utiliser truncate table :

TRUNCATE TABLE 
65
Thomas Mueller

Comme cette réponse est le premier résultat de Google pour "réinitialiser la base de données H2", je publie ma solution ci-dessous: 

Après chaque JUnit @tests :

  • Désactiver la contrainte d'intégrité
  • Lister toutes les tables dans le schéma PUBLIC (par défaut)
  • Tronquer toutes les tables
  • Répertorie toutes les séquences du schéma PUBLIC (par défaut)
  • Réinitialiser toutes les séquences
  • Réactiver les contraintes.

    @After
    public void tearDown() {
        try {
            clearDatabase();
        } catch (Exception e) {
            Fail.fail(e.getMessage());
        }
    }
    
    public void clearDatabase() throws SQLException {
        Connection c = datasource.getConnection();
        Statement s = c.createStatement();
    
        // Disable FK
        s.execute("SET REFERENTIAL_INTEGRITY FALSE");
    
        // Find all tables and truncate them
        Set<String> tables = new HashSet<String>();
        ResultSet rs = s.executeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES  where TABLE_SCHEMA='PUBLIC'");
        while (rs.next()) {
            tables.add(rs.getString(1));
        }
        rs.close();
        for (String table : tables) {
            s.executeUpdate("TRUNCATE TABLE " + table);
        }
    
        // Idem for sequences
        Set<String> sequences = new HashSet<String>();
        rs = s.executeQuery("SELECT SEQUENCE_NAME FROM INFORMATION_SCHEMA.SEQUENCES WHERE SEQUENCE_SCHEMA='PUBLIC'");
        while (rs.next()) {
            sequences.add(rs.getString(1));
        }
        rs.close();
        for (String seq : sequences) {
            s.executeUpdate("ALTER SEQUENCE " + seq + " RESTART WITH 1");
        }
    
        // Enable FK
        s.execute("SET REFERENTIAL_INTEGRITY TRUE");
        s.close();
        c.close();
    }
    

L'autre solution consisterait à recréer la base de données au début de chaque test. Mais cela pourrait être trop long en cas de gros DB.

19
Nils Renaud

Il existe une syntaxe spéciale dans Spring pour la manipulation de bases de données dans les tests unitaires

@Sql(scripts = "classpath:drop_all.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@Sql(scripts = {"classpath:create.sql", "classpath:init.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public class UnitTest {}

Dans cet exemple, nous exécutons drop_all.sql script (où nous supprimons toutes les tables requises) après chaque méthode de test . Dans cet exemple, nous exécutons create.sql script (où nous créons toutes les tables requises) et init.sql script (où nous initions toutes les tables requises before chaque méthode de test.

2
oleg.cherednik

La commande: SHUTDOWN
Vous pouvez l'exécuter à l'aide de RunScript.execute (jdbc_url, utilisateur, mot de passe, "classpath: shutdown.sql", "UTF8", false);
Je le lance à chaque fois que la suite de tests est terminée avec @AfterClass

2
dsantaolalla

Si vous utilisez un démarrage à ressort, voyez cette question stackoverflow

  1. Configurez votre source de données. Je n'ai pas de fermeture spéciale à la sortie. 

    la source de données: driverClassName: org.h2.Driver url: "jdbc: h2: mem: psptrx"

  2. Annotation @DirtiesContext de démarrage de printemps

    @DirtiesContext (classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

  3. Utilisez @Avant pour initialiser chaque cas de test. 

@DirtiesContext entraînera la suppression du contexte h2 entre chaque test.

1
Interlated

vous pouvez écrire dans le fichier application.properties le code suivant pour réinitialiser vos tables chargées par JPA:

spring.jpa.hibernate.ddl-auto=create
0
Mohamad Alesmaeil