Spring,Hibernate,HSQLDB:JUnit测试用例在主线程完成但第二个异步线程处理

时间:2016-11-14 21:54:49

标签: spring multithreading hibernate junit hsqldb

我有一个在Hibernate之上使用Spring的项目。 HSQLDB充当JUnit单元测试的数据库。经常(50%的时间)我们的构建在达到特定端点后挂起。

我测试的一个端点会在退出之前触发异步线程以进行一些清理工作。它不能从端点的开头触发,因为它取决于主线程的结果。请考虑以下代码:

@Transactional
public fooObj findCustomerFoo(Customer cust) {
    CustFooCollection custFooCollection = otherService.getCustomerFoo(cust);
    cleanupFooService.cleanupFoo(custFooCollection.getBadFoo());
    return custFooCollection.getGoodFoo(); //return to the webservice layer that 
    ///populates the response object and kicks it out
}

然后在CleanupFooService中你有了cleanupFoo方法:

@Async
@Transactional
public void cleanupFoo(List<Foo> foo) {
    //1) Pulls foo from DB
    //2) Runs state change and business logic on foo
    //3) Saves objects back in DB
}

代码的想法是findCustomerFoo触发所有必需的代码来拉取我所有的foo对象。在此期间,一些过滤继续进行,并且foos被过滤成两个不同的类别,返回调用者的好foos和需要状态更改和更新的坏foos。

出于性能原因,我们不希望在请求中进行清理,因为那里有一些逻辑和双重检查。这可以安全地发生在幕后。

我们的构建机器最近有一些变化,它暴露了我们的单元测试的问题。通常当这个端点作为测试的一部分被命中时,主线程(运行findCustomerFoo)在第二个线程(cleanupFoo)之前完成。当发生这种情况时,构建会挂起。在日志中我可以看到cleanupFoo已经开始调用数据库但尚未返回。我不知道查询是否在飞行中并等待数据库响应,如果hibernate仍在准备查询,或者hibernate仍在处理结果。我知道该线程当前在存储库方法中来处理进入数据库的过程。

在我们成功的构建中,我可以看到主线程在异步线程之后完成。这是由于Web服务层末尾的日志。在挂起测试中,此日志发生在异步线程中存在的日志之前。

此代码已在生产中运行一段时间而没有打嗝。

我的运行理论是,由于主线程完成JUnit / Spring开始取消HSQLDB导致第二个线程挂起。因为它仍然看到运行代码的线程,它不允许下一个单元测试或类开始运行。

我该怎么做才能阻止这些挂起?最初的测试用例作者将内存数据库在@Before的annoitated测试类中进行了初始化,然后在.sql文件中存在数据。我修复了那些指向xml配置中描述的数据源并使用ScriptUtils来运行种子数据文件。我的理论是,如果我的数据源的设置和拆除由弹簧100%控制,它可能会在退出之前识别线程的存在。但是,执行此操作并删除关闭数据源的后测试方法不起作用。

1 个答案:

答案 0 :(得分:0)

首先,数据库必须在操作开始之前处于活动状态,并且在此期间不会关闭。

如果与HSQLDB的连接似乎挂起,那是因为一个连接在一个事务中而另一个连接正在等待它完成。确保每组操作都是提交或回滚的事务。请注意,如果线程正在执行DDL语句,它将等待所有其他连接都已提交,然后在每个DDL操作期间锁定整个数据库。