2015-04-03 2 views
2

Короче говоря, я пытаюсь решить, как восстановить некоторые ошибки базы данных в приложении Grails с помощью Hibernate и продолжить транзакцию, пропуская неудачные обновления строк, которые часть партии изменений.Как исправить ошибки базы данных в Grails внутри транзакции

Приложение использует Grails 2.3.11, но я также пробовал с версией 1.3.8 с аналогичными неудачными результатами.

В основном существует класс обслуживания Grails, который выполняет итерацию по списку импортированных записей и пытается соответствующим образом обновлять связанные основные записи. В определенных ситуациях могут возникать исключения во время звонка domain.save(flush:true). org.hibernate.exception.DataException выброшено из-за таких проблем, как (Усечение данных: слишком длинные данные для столбца ...).

На данный момент я попытался:

  • Отключение транзакций
  • Использование domainObj.withTransaction() для каждой отдельной записи
  • Trying различные @Transactional аннотаций
  • Calling domain.clearErrors() и domain.discard() после исключения исключения
  • Пробовал с помощью вложенной службы с транзакционной аннотацией с noRollbackFor, как показано ниже
  • Рядом других подходов, но ничего я пробовал работал

Пример код:

@Transactional 
class UpdateService { 
    public updateBatch(Integer batchId) { 
     ... 
     list.each { record -> 
      record.value = 123 
      try { 
       nestedService.saveDomain() 
      } catch (e) { 
       record.clearErrors() 
       record.discard() 
      } 
     } 
     batch.status = "POSTED" 
     batch.save() 
    } 
} 

@Transactional 
class NestedService { 

    @Transactional(propagation = Propagation.REQUIRED, noRollbackFor = RuntimeException.class) 
    public void saveDomain(domainObj) throws RuntimeException { 
     if (domainObj.validate() && domainObj.save(flush:true) { 
      log.info "domain $domain was saved" 
     } 
    } 
} 

После произошла ошибка, я не могу очистить сеанс спящего режима. При каждой последующей обновляемой записи я получаю сообщение об ошибке:

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction 

, где он указывает исходный номер отказавшего домена.


Редакция:

Вахид, спасибо за предложения. Я пробовал это. Я понял, что одна проблема заключается в том, что я передаю объекты через границы транзакций. Так что я экспериментировал с классом NestedService сделать что-то вдоль линий:

@Transactional(propagation = Propagation.REQUIRE_NEW) 
public void saveDomain(domainObj) { 
    def newObj = new Domain.get(domainObj.id) 
    newObj.properties = domainObj.properties 
    if (newObj.validate() && newObj.save(force:true)) { ... } 

я ожидал, что работать, но оригинальный domainObj все еще терпит неудачу, хотя я не называю сохранения на нем. Очень странно ...

+0

попробовал REQUIRES_NEW для вашего распространения? Я добавил несколько заметок о кислоте здесь https://github.com/vahidhedayati/documentation/blob/master/grails/acid.md, недавно прочитав это http://blog.perezalcolea.info/2014/06/09/Grails- Транзакции-Revisited.html и этот http: // sacharya.com/transaction-in-grails/ – Vahid

+0

Vahid - посмотрите мои комментарии в исходных комментариях, где я добавил ревизию. –

+0

Что делать, если вы попытались newObj.merge() перед проверкой и сохранением, также вам удалось прочитать последнюю часть 3-й ссылки о пакетной обработке в спящем режиме. Однако никогда не рекомендовал бы его для Контроллеров. Если у вас есть время https://www.youtube.com/watch?v=JNey9T--rLE watch, Берт объясняет транзакции действительно хорошо. Нужно смотреть его несколько раз больше. – Vahid

ответ

0

Простым подходом будет цикл, а затем использовать validate(). Если это не удается, просто сохраните идентификатор отказавшего объекта и продолжите его.

if(!domainObject.validate()){ 
    // store Id for trying it again later ? 
}else{ 
    // Save 
} 
+0

Проблема у меня в том, что она получает текущие ограничения домена, поэтому validate() возвращает true. Проблема в том, что save() не удалось и автоматически откатывает всю транзакцию, независимо от аннотации noRollbackFor. После возникновения ошибки каждое последующее обновление выходит из строя. Это довольно странно ... –

+0

Если вы используете Transactional Annotation на уровне Action/Function, попробуйте не использовать его в определении Service (установите его как false). По умолчанию все службы трансаляционные, поэтому вам не нужно явно определять его как транзакцию. Посмотрите раздел «Услуги Grails» в [http://grails.github.io/grails-doc/3.0.x/guide/services.html]. – vivwilfer

Смежные вопросы