3

考虑以下代码:

if (!serpKeyword) {
    serpKeyword = new SerpKeyword(
            keyword: searchKeyword,
            geoKeyword: geoKeyword,
            concatenation: concatenation,
            locale: locale
    )
    serpKeyword.save(flush: true, failOnError: true)
}

serpService.submitKeyword(serpKeyword, false)

这是 submitKeyword 方法:

@Transactional(propagation = Propagation.REQUIRES_NEW)
boolean submitKeyword(keywordToSubmit, boolean reset) {
    def keyword = SerpKeyword.get(keywordToSubmit.id)

调用时没有引发错误serpKeyword.save,但是当我进入该submitKeyword方法时,SerpKeyword.get(keywordToSubmit.id)返回 null。是什么阻止了它的保存?

编辑

更改REQUIRES_NEWREQUIRED似乎可以解决问题。这就是我认为正在发生的事情。

调用的代码serpService.submitKeyword位于服务方法中。据我了解,服务方法的默认传播策略是REQUIRED. 由于所有这些数据库写入都发生在事务的上下文中,因此写入在数据库中排队,但在事务完成之前并未实际对数据库执行,根据文档

请注意,刷新与提交事务不同。如果您的操作是在事务的上下文中执行的,则刷新将执行 SQL 更新,但数据库会将更改保存在其事务队列中,并且仅在事务提交时才完成更新。

serpService.submitKeyword我们在事务实际完成之前调用。serpKeyword该方法在我们不可用的情况下启动一个全新的事务。将其更改为REQUIRED有效,因为我们现在在父事务的上下文中进行操作。

4

1 回答 1

0

我认为堆栈的某些部分是懒惰的。如果您使用的是 Hibernate,我已经遇到过这种行为。我不确定这是一个被批准的动作,但你可以在调用之前清除会话,submitKeyword如下所示:

long keywordId = serpKeyword.id
SerpKeyword.withSession{it.clear()}
serpService.submitKeyword(keywordId, false)

然后将方法更改为:

@Transactional(propagation = Propagation.REQUIRES_NEW)
boolean submitKeyword(keywordId, boolean reset) {
  def keyword = SerpKeyword.get(keywordId)

然后我打赌.get()意志会奏效。如果您在会话中有其他需要的对象。您将需要通过存储它们的 id 和.get()ing 来解除它们。

于 2013-04-14T00:44:48.297 回答