【发布时间】:2013-04-13 02:01:27
【问题描述】:
我经常使用内存中的 HSQL 数据库作为测试数据库来编写依赖于数据库的代码的单元测试。最近我决定从 1.8.1.3 升级到 2.2.9,以利用 2.x 发布分支中添加的 ROW_NUMBER() 支持。
似乎在某些方面,新版本比旧版本更严格。使用 Hibernate (3.6.10) 作为 ORM,例如,我可能会创建一个 Configuration 对象来创建第一个 SessionFactory,使用它来填充测试数据,然后将 Configuration 用于被测类,这创建它自己的SessionFactory 来进行选择。使用 hsqldb 1.8.1.3,没问题。在 2.2.9 中,选择块在 hsqldb 代码中。下面是一个展示这一点的 SSCCE:
public void testTwoSessionFactories() throws Exception {
boolean withTx = false;
AnnotationConfiguration config = new AnnotationConfiguration().addAnnotatedClass(Entity.class);
config.setProperty("hibernate.hbm2ddl.auto", "create");
config.setProperty(Environment.DIALECT, HSQLDialect.class.getName());
config.setProperty(Environment.DRIVER, jdbcDriver.class.getName());
config.setProperty(Environment.URL, "jdbc:hsqldb:mem:testDB");
config.setProperty(Environment.USER, "SA");
config.setProperty(Environment.PASS, "");
SessionFactory sessionFactory1 = config.buildSessionFactory();
Session session = sessionFactory1.openSession();
Transaction tx = null;
if (withTx)
tx = session.beginTransaction();
session.save(new Entity("one"));
if (withTx)
tx.commit();
session.flush();
session.close();
config.setProperty("hibernate.hbm2ddl.auto", "");
SessionFactory sessionFactory2 = config.buildSessionFactory();
Session session2 = sessionFactory2.openSession();
List entities = session2.createCriteria(Entity.class).list();
session2.close();
}
注意withTx 布尔值。使用 HSQLDB 1.8.1.3,我可以使用withTx true 或 false 运行此代码,它会没事的。在 HSQLDB 2.2.9 中,withTx 必须设置为 true,否则线程会在使用以下堆栈的 .list() 调用中被阻塞:
Unsafe.park(boolean, long) line: not available [native method]
LockSupport.park(Object) line: not available
CountDownLatch$Sync(AbstractQueuedSynchronizer).parkAndCheckInterrupt() line: not available
CountDownLatch$Sync(AbstractQueuedSynchronizer).doAcquireSharedInterruptibly(int) line: not available
CountDownLatch$Sync(AbstractQueuedSynchronizer).acquireSharedInterruptibly(int) line: not available
CountDownLatch.await() line: not available
CountUpDownLatch.await() line: not available
Session.executeCompiledStatement(Statement, Object[]) line: not available
Session.execute(Result) line: not available
JDBCPreparedStatement.fetchResult() line: not available
JDBCPreparedStatement.executeQuery() line: not available
BatchingBatcher(AbstractBatcher).getResultSet(PreparedStatement) line: 208
CriteriaLoader(Loader).getResultSet(PreparedStatement, boolean, boolean, RowSelection, SessionImplementor) line: 1953
CriteriaLoader(Loader).doQuery(SessionImplementor, QueryParameters, boolean) line: 802
CriteriaLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor, QueryParameters, boolean) line: 274
CriteriaLoader(Loader).doList(SessionImplementor, QueryParameters) line: 2542
CriteriaLoader(Loader).listIgnoreQueryCache(SessionImplementor, QueryParameters) line: 2276
CriteriaLoader(Loader).list(SessionImplementor, QueryParameters, Set, Type[]) line: 2271
CriteriaLoader.list(SessionImplementor) line: 119
SessionImpl.list(CriteriaImpl) line: 1716
CriteriaImpl.list() line: 347
EntityTest.testTwoSessionFactories() line: 46
HSQLDB 在 1.8.1.3 和 2.2.9 之间发生了哪些变化,需要此代码在事务中进行保存,我可以将其关闭吗?
【问题讨论】:
-
每个数据库交互都应该在事务中完成。这就是 Hibernate 文档的建议。我只是修复错误并确保您始终使用事务。另外,你为什么使用两个不同的会话工厂?没有理由这样做。会话工厂是一个重量级的对象,应该一劳永逸地创建。 +1 用于清晰的单元测试。
-
@JBNizet Re:事务,在生产代码中我总是这样做,但在测试设置代码中我比较松散,因为我认为它只会给测试增加混乱。还不错,但我无法改变它!
-
@JBNizet 回复:会话工厂,因为被测试的类(在这种情况下)负责创建和维护会话工厂。第一个会话工厂是设置测试数据。在其他情况下,被测类接受一个 Session 或被赋予一个 SessionFactory,然后只有一个 SessionFactory。
标签: java hibernate jdbc hsqldb