定期重置Embedded H2数据库

jav*_*csw 42 h2 reset

我正在一个演示服务器中设置我的应用程序的新版本,并希望找到一种每天重置数据库的方法.我想我总是可以执行一个cron作业执行drop并创建查询,但我正在寻找一种更清洁的方法.我尝试使用具有drop-create方法的特殊持久性单元,但它不起作用,因为系统经常连接和断开服务器(按需).

有更好的方法吗?

Tho*_*ler 73

H2支持一个特殊的SQL语句来删除所有对象:

DROP ALL OBJECTS [DELETE FILES]
Run Code Online (Sandbox Code Playgroud)

如果您不想删除所有表,则可能需要使用truncate table:

TRUNCATE TABLE 
Run Code Online (Sandbox Code Playgroud)

  • TRUNCATE TABLE不会将AUTO_INCREMENT计数器重置为零:( (3认同)
  • @Nazar,是的,这与其他数据库的行为相同,例如PostgreSQL(使用`serial`).我认为这是正确的行为,因为值可能会在其他表中使用. (2认同)

Nil*_*aud 20

由于此响应是"重置H2数据库"的第一个Google结果,我在下面发布了我的解决方案:

在每个JUnit @tests之后:

  • 禁用完整性约束
  • 列出(默认)PUBLIC模式中的所有表
  • 截断所有表格
  • 列出(默认)PUBLIC模式中的所有序列
  • 重置所有序列
  • 重新启用约束.

    @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();
    }
    
    Run Code Online (Sandbox Code Playgroud)

另一种解决方案是在每次测试开始时重新创建数据库.但是对于大数据库来说,这可能太长了.


ole*_*nik 7

Spring 中有特殊的语法用于单元测试中的数据库操作

@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 {}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我们每个测试方法之后执行drop_all.sql脚本(我们删除所有需要的表)。在这个例子中,我们执行create.sql脚本(我们在其中创建所有必需的表)和init.sql脚本(我们每个测试方法之前初始化所有必需的表)。

  • 这是我为此类问题找到的最简单、最直观的解决方案。 (2认同)