我想在一个集成测试与另一个集成测试之间截断所有数据库表。使用hibernate执行此操作的最佳方法是什么?
目前我正在这样做:
public void cleanDatabase() {
doWithSession(new Action1<Session>() {
@Override
public void doSomething(Session session) {
SQLQuery query = session.createSQLQuery("truncate table stuff");
// todo - generify this to all tables
query.executeUpdate();
}
});
(doWithSession是一个创建和关闭会话的小包装器)。我可以使用反射迭代我所有的映射对象......我想知道是否有人已经解决了这个问题。
答案 0 :(得分:3)
我猜你可能不会使用Spring。如果你这样做,Spring's transactional test support将是理想的。
简而言之:Spring会在每个测试用例之前自动启动一个事务,并在测试用例之后自动回滚,从而为您留下一个空的(或至少不变的)数据库。
也许你可以模仿这种机制:
使用@Before
方法打开一个事务,然后使用@After
方法回滚。
答案 1 :(得分:0)
你在内存mysql http://dev.mysql.com/downloads/connector/mxj/看了吗?每次测试后都不可能回滚吗?我相信你可以像这样配置它。
答案 2 :(得分:0)
您可以使用SchemaExport删除并重新创建Hibernate架构,尽管这看起来非常严厉。回滚交易听起来更好。
答案 3 :(得分:0)
您可以使用内存数据库并在测试之间删除完整的数据库。
如果没有那么多但是很长的测试,你可以使用这种方式。
但请注意,每个数据库的行为都与其他数据库略有不同。因此,在某些情况下,使用内存数据库(例如HyperSQL)的行为与普通数据库完全不同 - 因此它不是正确的集成测试。
答案 4 :(得分:0)
我正是为此目的而写了一个积分器。基本上,我们进入了会话工厂创建流程,遍历了Hibernate找到的表映射,并对每个表执行TRUNCATE TABLE xxx
。由于我们无法用外键约束截断表,因此在截断操作之前禁用外键检查,然后重新启用。
static final class TruncatorIntegrator implements org.hibernate.integrator.spi.Integrator {
@Override
public void integrate(Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
try (Session session = sessionFactory.openSession()) {
session.doWork(connection -> {
try (PreparedStatement preparedStatement = connection.prepareStatement("SET FOREIGN_KEY_CHECKS = 0;")) {
preparedStatement.executeUpdate();
System.out.printf("Disabled foreign key checks%n");
} catch (SQLException e) {
System.err.printf("Cannot disable foreign key checks: %s: %s%n", e, e.getCause());
}
metadata.collectTableMappings().forEach(table -> {
String tableName = table.getQuotedName();
try (PreparedStatement preparedStatement = connection.prepareStatement("TRUNCATE TABLE " + tableName)) {
preparedStatement.executeUpdate();
System.out.printf("Truncated table: %s%n", tableName);
} catch (SQLException e) {
System.err.printf("Couldn't truncate table %s: %s: %s%n", tableName, e, e.getCause());
}
});
try (PreparedStatement preparedStatement = connection.prepareStatement("SET FOREIGN_KEY_CHECKS = 1;")) {
preparedStatement.executeUpdate();
System.out.printf("Enabled foreign key checks%n");
} catch (SQLException e) {
System.err.printf("Cannot enable foreign key checks: %s: %s%n", e, e.getCause());
}
});
}
}
@Override
public void disintegrate(SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
}
}
用法:我们必须在会话工厂创建流程中使用此Integrator
,并且还需要为每个测试创建一个新的会话工厂。
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().applyIntegrator(new TruncatorIntegrator()).build();
StandardServiceRegistry registry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry).build();
SessionFactory sessionFactory = new Configuration().buildSessionFactory(registry);