it-swarm-pt.tech

Redefinir o banco de dados H2 incorporado periodicamente

Estou configurando uma nova versão do meu aplicativo em um servidor de demonstração e adoraria encontrar uma maneira de redefinir o banco de dados diariamente. Eu acho que sempre posso ter um cron job executando drop e criar consultas, mas estou procurando uma abordagem mais limpa. Eu tentei usar uma unidade de persistência especial com a abordagem drop-create, mas não funciona como o sistema se conecta e desconecta do servidor com freqüência (sob demanda).

Existe uma abordagem melhor?

38
javydreamercsw

H2 suporta uma instrução SQL especial para soltar todos os objetos :

DROP ALL OBJECTS [DELETE FILES]

Se você não quiser descartar todas as tabelas, você pode querer usar truncate table :

TRUNCATE TABLE 
65
Thomas Mueller

Como essa resposta é o primeiro resultado do Google para "redefinir o banco de dados H2", eu postei minha solução abaixo: 

Depois de cada JUnit @tests :

  • Desativar restrição de integridade
  • Listar todas as tabelas no esquema PUBLIC (padrão)
  • Truncar todas as tabelas
  • Listar todas as sequências no esquema PUBLIC (padrão)
  • Repor todas as sequências
  • Reabilite as restrições.

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

A outra solução seria recriar o banco de dados no início de cada teste. Mas isso pode ser muito longo em caso de grande DB.

19
Nils Renaud

Thre é uma sintaxe especial no Spring para manipulação de banco de dados dentro de testes unitários

@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 {}

Neste exemplo, executamos drop_all.sql script (onde droppamos todas as tabelas requeridas) after todo método de teste. Neste exemplo, executamos create.sql script (onde criamos todas as tabelas necessárias) e init.sql script (onde iniciamos todas as tabelas necessárias antes cada método de teste.

2
oleg.cherednik

O comando: SHUTDOWN
Você pode executá-lo usando RunScript.execute (jdbc_url, usuário, senha, "classpath: shutdown.sql", "UTF8", false);
Eu o executo sempre que a Suíte de testes é concluída usando @AfterClass

2
dsantaolalla

Se você estiver usando boot de mola, veja este stackoverflow question

  1. Configure sua fonte de dados. Eu não tenho nenhum fechamento especial na saída. 

    fonte de dados: driverClassName: org.h2.Driver url: "jdbc: h2: mem: psptrx"

  2. Anotação Spring boot @DirtiesContext

    @DirtiesContext (classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

  3. Use @Before para inicializar em cada caso de teste. 

O @DirtiesContext fará com que o contexto h2 seja descartado entre cada teste.

1
Interlated

você pode escrever no application.properties o código a seguir para redefinir suas tabelas que são carregadas pelo JPA:

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