我正在尝试实施以下方案:
class A {
...
static hasMany = [bees: B]
}
class B {
static belongsTo = [a: A]
}
现在,我们一次创建大约10,000个属于A的B(来自服务)实例,但是如果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次失败的所有内容。
答案 0 :(得分:0)
您的服务需要是交易性的(将grails @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
}
}
使用批处理时需要注意的是确保会话不会变得太大。您可以通过获取当前会话的句柄然后刷新并清除它来阻止它:
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
}
}