2014-02-19 4 views
2

Я пытаюсь выполнить следующий сценарий:Grails ручных операций и откатить

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

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

Теперь мы создаем около 10 000 экземпляров 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() 
    } 
} 

Может кто-нибудь помочь, как я могу создать большие объемы элемента в отношениях/belongsTo hasMany, но откатить все при ошибке 1, из класса обслуживания.


+0

точки 3 из [этого ответа] (http://stackoverflow.com/a/17357547/2051952) является то, что я предположим, это лучший вариант для вас в этом случае, если вы используете услуги grails. – dmahapatro

ответ

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 
     } 
    } 
Смежные вопросы