【问题标题】:How to create new transaction within existing transaction in Grails如何在 Grails 中的现有事务中创建新事务
【发布时间】:2013-07-09 16:09:03
【问题描述】:

我有机器和零件域类

在我的服务类中,我试图启动一个事务,在该事务中我想创建一个新事务并在它从内部事务中出来时提交它。

Machine.withTransaction { // transaction 1
    // some code to add Parts

    // some code to remove Parts
    Machine.withNewTrasaction { // transaction 2
       // some code to remove Parts.
    } // end of transaction 2

// some code to update couple of columns in machine table.
}// end of transaction 1

当它来自transaction 2 时,我希望transaction 2 被提交给机器的零件,而不考虑transaction 1。但是grails 将错误返回为"Illegal attempt to associate a collection with two open sessions" 如何单独提交transaction 2而不考虑transaction 1

【问题讨论】:

  • 你可以试试Machine.withNewTransaction(propagation: TransactionDefinition.PROPAGATION_REQUIRES_NEW){...}吗?
  • @dmahapatro 我收到错误,因为No signature of method : Machine.withNewTransaction 我觉得语法或有问题。我也找不到很好的文档

标签: grails transactions


【解决方案1】:

您可以尝试在服务类中使用@Transactional 注释显式处理事务。

注意事项:-

  • @Transactional 注解添加到服务方法后,默认情况下服务类不会被视为事务类。
  • 由于您将功能拆分为两个方法,您必须使用服务类的proxied 实例来调用第二种方法,否则您无法为第二种方法创建新事务。因此,在方法 1 中使用下面的applicationContext
  • 您将不再需要 withTransactionwithNewTransaction 阻止。

服务类看起来像:

class MachineService{
   @Transactional
   def someMethodToAddParts(){
       ......
       grailsApplication.mainContext.machineService.someMethodToRemoveParts()
       ......
   }

   @Transactional(propagation = TransactionDefinition.PROPAGATION_REQUIRES_NEW)
   def someMethodToRemoveParts(){
     .......
   }
}

【讨论】:

  • 我用这种方式试了代码public boolean someMethodToAddParts() { withTransaction{ ... grailsApplication.mainContext.machineService.someMethodToRemoveParts() ... } } @Transactional(propagation = TransactionDefinition.PROPAGATION_REQUIRES_NEW) protected boolean someMethodToRemoveParts(){ ... parts.save() }
  • 在我的第一种方法中,如果设置了事务回滚或任何其他与此相关的错误,它应该通过 someMethodToRemoveParts 保留 Parts 表。但是,当来自 someMethodToAddParts() 的响应出现错误时,它没有将这些部分保留在 DB 中。我错过了什么吗?
  • @user2001627 someMethodToRemoveParts() 不是要删除零件而不是保留它吗?如果您使用注解,则无需提供withTransaction
  • 感谢您的回复。是的,它必须删除从机器中删除部件的部件(可能在代理对象中),但如果someMethodToAddParts() 设置回滚,它不会提交。不管怎样,我都在期待,PROPAGATION_REQUIRES_NEW 已经设置好了,所以它会在流出来后在 DB 中提交它someMethodToAddParts()
【解决方案2】:

我遇到了一个稍微不同的问题,也许它可以帮助某人,也许它可以帮助解决上述问题。

我认为可以通过将实体合并到新事务中来避免上述问题,然后在导致问题的集合上使用 .merge() 方法。

首先我觉得上面的代码是这样的(我加了cmets来解释):

Machine.withTransaction { // transaction 1
    // some code to add Parts

    yourEntity.addToParts(...)

    // some code to remove Parts
    Machine.withNewTrasaction { // transaction 2
       // some code to remove Parts.

       yourEntity.removeFromParts(...)


    } // end of transaction 2 -> the session is flushed, and the transaction is committed
      // during the flush, hibernate detect that "parts" collection is already attached
      // to another session, in another transaction then throw "Illegal 
      // attempt to associate a collection with two open sessions"

// some code to update couple of columns in machine table.
}

然后解决方案是将集合合并到新事务中,它给我们这样的东西:

Machine.withTransaction { // transaction 1
    // some code to add Parts

    yourEntity.addToParts(...)

    // some code to remove Parts
    Machine.withNewTrasaction { // transaction 2
       // some code to remove Parts.

       yourEntity.removeFromParts(...)
       // Merging the collection to the session
       yourEntity.merge() // I haven't tried but maybe you need ensure 
                          // there is a merge cascade on "parts" collection

    } // end of transaction 2 -> the session is flushed, and the transaction is committed

// some code to update couple of columns in machine table.
}

在我的情况下,通过新事务中的合并,我解决了错误消息“具有相同标识符值的不同对象已与会话关联:[yourPackage.YourEntity]”(当我谈论 YourEntity 时,您也可以读YourDomaineClass)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 2022-10-08
    • 1970-01-01
    • 1970-01-01
    • 2020-10-20
    相关资源
    最近更新 更多