在hsqldb 1.8.1.3之上的基于Hibernate的代码的单元测试不再适用于hsqldb 2.2.9 [英] Unit tests of Hibernate based code on top of hsqldb 1.8.1.3 no longer work on hsqldb 2.2.9

查看:273
本文介绍了在hsqldb 1.8.1.3之上的基于Hibernate的代码的单元测试不再适用于hsqldb 2.2.9的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常使用内存中的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();

交易tx = null;
if(withTx)
tx = session.beginTransaction();

session.save(新实体(一));

if(withTx)
tx.commit();

session.flush();
session.close();

config.setProperty(hibernate.hbm2ddl.auto,);
SessionFactory sessionFactory2 = config.buildSessionFactory();
Session session2 = sessionFactory2.openSession();
列出实体= session2.createCriteria(Entity.class).list();
session2.close();

请注意 withTx 布尔值。使用HSQLDB 1.8.1.3,我可以用来运行这个代码,其中TX true或false,并且它会没事的。使用HSQLDB 2.2.9时,必须将 withTx 设置为true ,否则线程会被阻塞在 .list()



  Unsafe.park(boolean,long)行:不可用[本地方法] 
LockSupport.park(Object)行:不可用
CountDownLatch $ Sync(AbstractQueuedSynchronizer).parkAndCheckInterrupt()行:不可用
CountDownLatch $ Sync(AbstractQueuedSynchronizer).doAcquireSharedInterruptibly(int)行:不可用
CountDownLatch $ Sync(AbstractQueuedSynchronizer).acquireSharedInterruptibly(int)行:不可用
CountDownLatch.await()行:不可用
CountUpDownLatch.await()行:不可用
Session.executeCompiledStatement(Statement,Object [])行:不可用
Session.execute(结果)行:不可用
JDBCPreparedStatement.fetchResult()行:不可用
JDBCPreparedStatement。 executeQuery()行:不可用
BatchingB attrib(PreparedStatement)行:208 $ b $ CriteriaLoader ,布尔值)行:802
CriteriaLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor,QueryParameters,boolean)行:274 $ b $ CriteriaLoader(Loader).doList(SessionImplementor,QueryParameters)行:2542
CriteriaLoader Loader).listIgnoreQueryCache(SessionImplementor,QueryParameters)line:2276 $ b $ CriteriaLoader(Loader).list(SessionImplementor,QueryParameters,Set,Type [])line:2271
CriteriaLoader.list(SessionImplementor)line:119
SessionImpl.list(CriteriaImpl)行:1716
CriteriaImpl.list()行:347
EntityTest.testTwoSessionFactories()行:46

在1.8.1.3和2.2.9之间的HSQLDB中,我可以把它关闭吗?

解决方案

HSQLDB 1.8。 x 使用 READ UNCOMMITTED 来查看已被其他交易添加或更改的行。

HSQLDB 2.x 使用 READ COMMITTED (默认)或 SERIALIZABLE 隔离级别。因此,在更改可见之前,事务必须提交。还有交易模式需要考虑。

默认交易模型 LOCKS ,它锁定在事务提交之前被修改的表。您可以使用 MVCC模型,它允许其他会话从表中读取数据并修改尚未修改的行。您可以将此模型与 URL属性一起使用。

  config.setProperty (Environment.URL,jdbc:hsqldb:mem:testDB; hsqldb.tx = mvcc); 


I frequently write unit tests of my database dependent code using an in-memory HSQL database as the testing database. Recently I decided to upgrade from 1.8.1.3 to 2.2.9 to take advantage of ROW_NUMBER() support that was added in the 2.x release branch.

It seems that in some way, the new version is more strict than the old version. Using Hibernate (3.6.10) as the ORM, I might for example create a Configuration object to create a first SessionFactory, use that to populate the test data, then uses the Configuration to the class under test, which creates it's own SessionFactory to do a select. With hsqldb 1.8.1.3, no problem. With 2.2.9, the select blocks inside of hsqldb code. Below is a SSCCE demonstrating this:

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();
}

Note the withTx boolean. With HSQLDB 1.8.1.3, I can run this code with withTx true or false, and it'll be fine. With HSQLDB 2.2.9, withTx must be set to true, otherwise the thread gets blocked in the .list() call with the following stack:

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   

What changed in HSQLDB between 1.8.1.3 and 2.2.9 that requires this code to do the save within a transaction, and can I turn it off?

解决方案

HSQLDB 1.8.x uses READ UNCOMMITTED for rows that have been added or changed by another transaction.

HSQLDB 2.x uses READ COMMITTED (by default) or SERIALIZABLE isolation level. Therefore a transaction must commit before its changes are visible. There is also the transaction model to consider.

The default transaction model is LOCKS which locks a table that is modified until the transaction is committed. You can use the MVCC model instead, which allows other sessions to read from the table and to modify rows that have not been modified. You can use this model with a URL property.

config.setProperty(Environment.URL, "jdbc:hsqldb:mem:testDB;hsqldb.tx=mvcc");

这篇关于在hsqldb 1.8.1.3之上的基于Hibernate的代码的单元测试不再适用于hsqldb 2.2.9的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆