基于Hibernate的代码在hsqldb 1.8.1.3之上的单元测试不再适用于hsqldb 2.2.9

sha*_*kan 6 java hibernate jdbc hsqldb

我经常使用内存中的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代码中的select块.以下是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();
}
Run Code Online (Sandbox Code Playgroud)

注意withTx布尔值.使用HSQLDB 1.8.1.3,我可以使用withTxtrue或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   
Run Code Online (Sandbox Code Playgroud)

HSQLDB在1.8.1.3和2.2.9之间发生了哪些变化需要此代码在事务中进行保存,我可以将其关闭吗?

fre*_*edt 10

HSQLDB 1.8.x使用READ UNCOMMITTED对已被其他事务添加或更改的行.

HSQLDB 2.x使用READ COMMITTED(默认情况下)或SERIALIZABLE隔离级别.因此,事务必须在其更改可见之前提交.还有transaction model需要考虑的问题.

默认值transaction modelLOCKS锁定在提交事务之前修改的表.您可以使用MVCC model,它允许其他会话从表中读取并修改尚未修改的行.你可以使用这个模型URL property.

config.setProperty(Environment.URL, "jdbc:hsqldb:mem:testDB;hsqldb.tx=mvcc");
Run Code Online (Sandbox Code Playgroud)