1

我有一个流程需要构建一个 PDF 文档并将其与正在创建的 100 多个其他文档相结合。

我想多线程这个。我将需要生成的 PDF 并保存到数据库的事件列表传递给服务。文档也保存为目的地,路径保存到数据库。

所以我使用 10 个线程的 GPars。我遇到了一个问题,当我懒惰地从事件中提取时,我收到一条错误消息

未能延迟初始化角色集合:com.srm.billing.DepositNotice.depositNoticeRevisions,没有会话或会话已关闭;嵌套异常是 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.srm.billing.DepositNotice.depositNoticeRevisions, no session or session was closed

我注意到几个站点都在说 Hibernate 不是线程安全的,我认为这是导致问题的原因。

GParsPool.withPool( poolSize ) { forkJoinPool ->
            depositNotices = pEvents.collectParallel{ event -> 
                Event.withNewSession{ session ->
                    return buildDepositNotice( event )
                    session.flush()
                } 
            }
        }

byte[] findlDocument = null
        finalDocument = pdfUtilService.concatPDFs( depositNotices )

我看到的结果是,当发生此错误时,之前处理的事件将提交给数据库,这是一个问题。

我的最终目标是传递给方法的事件列表作为一个批次完成,如果 1 失败,则不会将任何记录提交到数据库。

4

1 回答 1

1

从技术上讲,collectParallel()旨在与无副作用的代码一起使用。但是您仍然可以谨慎使用它。

假设buildDepositNotice(Event)返回一个保存的域实例,当该实例在Event.withNewSession(Closure)闭包之外使用时,它将被分离。当实例分离时,您可以访问它的属性等,但要保留它,您必须首先将它重新附加到当前会话。

要收集存款通知,请确保该实例是withNewSession()闭包中评估的最后一个表达式。

Event.withNewSession{ session ->
    def depositNotice = buildDepositNotice(event)

    session.flush()
    depositNotice
} 

如果pdfUtilService.concatPDFs()需要保留存款通知,请确保它attach()首先调用存款通知。

于 2015-10-23T04:09:29.447 回答