【发布时间】:2012-01-21 08:17:45
【问题描述】:
我正在演示服务器中设置我的应用程序的新版本,并且很想找到一种每天重置数据库的方法。我想我总是可以有一个 cron 作业来执行 drop 和 create 查询,但我正在寻找一种更清洁的方法。我尝试使用具有 drop-create 方法的特殊持久性单元,但由于系统频繁(按需)连接和断开与服务器的连接,它不起作用。
有更好的方法吗?
【问题讨论】:
我正在演示服务器中设置我的应用程序的新版本,并且很想找到一种每天重置数据库的方法。我想我总是可以有一个 cron 作业来执行 drop 和 create 查询,但我正在寻找一种更清洁的方法。我尝试使用具有 drop-create 方法的特殊持久性单元,但由于系统频繁(按需)连接和断开与服务器的连接,它不起作用。
有更好的方法吗?
【问题讨论】:
H2支持对drop all objects的特殊SQL语句:
DROP ALL OBJECTS [DELETE FILES]
如果您不想删除所有表,您可能需要使用truncate table:
TRUNCATE TABLE
【讨论】:
serial)。我认为这是正确的行为,因为这些值可能会在其他表中使用。
JdbcDataSource ds = new JdbcDataSource(); ds.setURL("jdbc:h2:~/mydb"); ds.setUser("sa"); ds.setPassword("pass");...etc 我用它在我的 eclipse java 项目中创建一个嵌入式数据库。如何删除 db-mydb ?谢谢。
由于此响应是“重置 H2 数据库”的第一个 Google 结果,因此我在下面发布了我的解决方案:
在每个 JUnit @tests 之后:
重新启用约束。
@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();
}
另一种解决方案是在每次测试开始时重新创建数据库。但是对于大型数据库,这可能太长了。
【讨论】:
org.junit.rules.TestRule 中使用它 - 它会在每次测试之前重置数据库。
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 {}
在本例中,我们在每个测试方法之后执行 drop_all.sql 脚本(我们在其中删除所有必需的表)。 在此示例中,我们执行 create.sql 脚本(我们在其中创建所有必需的表)和 init.sql 脚本(我们在其中初始化所有必需的表 before 每种测试方法。
【讨论】:
如果您使用的是 Spring Boot,请参阅此stackoverflow question
设置您的数据源。我在退出时没有任何特别的关闭。
数据源: driverClassName: org.h2.Driver 网址:“jdbc:h2:mem:psptrx”
Spring boot @DirtiesContext 注解
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
使用@Before 对每个测试用例进行初始化。
@DirtiesContext 将导致在每次测试之间删除 h2 上下文。
【讨论】:
命令:SHUTDOWN
您可以使用
RunScript.execute(jdbc_url, user, password, "classpath:shutdown.sql", "UTF8", false);
我每次使用 @AfterClass 完成测试套件时都会运行它
【讨论】:
您可以在 application.properties 中编写以下代码来重置 JPA 加载的表:
spring.jpa.hibernate.ddl-auto=create
【讨论】: