我正在尝试实现以下方案:

class A {
    ...
    static hasMany = [bees: B]
}

class B {
    static belongsTo = [a: A]
}

现在,我们一次创建了大约10,000个B(通过服务)属于A的实例,但是如果1失败,它将回滚所有成功创建的实例。我尝试了几种方法,但都无效:
try {
    for (int i = 0; i < batch.numToMake; i++) {
        def b = new B().save(flush: i % 1000 == 0)

        if (i == 50) {
            throw new RuntimeException("simulate")
        }
    }

    batch.status = Constants.BATCH_STATUS_DONE
    batch.save(flush: true)
} catch (e) {
    // This was a last resort test and still did not work
    batch.status = Constants.BATCH_STATUS_FAILED
    batch.vouchers.each {
        batch.removeFromVouchers(it)
    }

    batch.save(flush: true)
}
// This did not work at all
B.withTransaction { status ->
    try {
        for (int i = 0; i < batch.numToMake; i++) {
            def b = new B().save(flush: i % 1000 == 0)

            if (i == 50) {
                throw new RuntimeException("simulate")
            }
        }
    } catch (e) {
        status.setRollbackOnly()
    }
}

任何人都可以帮助我如何在hasMany / belongsTo关系中创建大量项目,但是如果服务类失败,则在失败1时回滚所有内容。

最佳答案

您的服务需要是事务性的(在服务类的顶部放上@Transactional注释),那么您就不需要尝试/捕获。从该方法引发的任何RuntimeException都会触发事务回滚。
因此,您只需执行以下操作:

def import() {
    def a = A.get(1L)
    for (int i = 0; i < 1000; i++) {
        new B(a: a).save()

        // runtime exception thrown here would rollback everything
    }
}

使用批处理时,您需要注意的是确保 session 不会变得太大。您可以通过获取当前 session 的句柄然后刷新并清除它来防止这种情况:
def import() {
    Parent.withSession { session ->
        def a = A.get(1L)
        for (int i = 0; i < 10000; i++) {
            new B(a: a).save()

            // runtime exception thrown here would rollback everything

            if (i % 100 == 0) {
                session.flush()
                session.clear()
            }

            // runtime exception thrown here would rollback everything
        }
    }

关于grails - Grails手动交易和回滚,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21890041/

10-14 06:19