我正在尝试实现以下方案:
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/