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?
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
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 :
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.
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.
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
Si vous utilisez un démarrage à ressort, voyez cette question stackoverflow
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"
Annotation @DirtiesContext de démarrage de printemps
@DirtiesContext (classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
Utilisez @Avant pour initialiser chaque cas de test.
@DirtiesContext entraînera la suppression du contexte h2 entre chaque test.
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