Grails (2.3) @Transactional не выполняет откат

Откат выполняется здесь, как и ожидалось:

@Transactional(propagation = Propagation.REQUIRES_NEW)
def test1() {
  def dummy = new Dummy(name: "test1")
  dummy.save()
  throw new RuntimeException("test1!")
}

Но здесь нет — что, вероятно, неправильно — try/catch не должен влиять на поведение:

@Transactional(propagation = Propagation.REQUIRES_NEW)
def test2() {
  def dummy = new Dummy(name: "test2")
  dummy.save()
  try {
    throw new RuntimeException("test2!")
  } catch (all) {
    println all.message
  }
}

person J.T.    schedule 16.02.2017    source источник


Ответы (2)


По умолчанию @Transactional оборачивает метод таким образом, что любое непроверенное исключение (а именно, RuntimeException) вызовет откат транзакции.

Если вы поймаете/обработаете исключение в методе, конечно, исключение не распространяется на оболочку транзакции, и транзакция не будет помечена как откатная. Кажется, это то, что вы делаете.

Стоит отметить, что вы можете указать, что транзакционная оболочка должна откатывать транзакции, если возникают другие исключения (и распространяться на оболочку). Вы можете сделать это с помощью параметра аннотации rollbackFor.

Например,

@Transactional(rollbackFor=Throwable.class)
void doTransactionalWork() throws MyException { ... }

приведет к откату транзакции, если какие-либо Throwable распространяются до оболочки, даже те, которые проверены (а именно, MyException)

Таким должно быть поведение любого метода @Transactional, независимо от того, создаете ли вы новую транзакцию или наследуете существующий транзакционный контекст.

person jstell    schedule 17.02.2017

возможно, вы неправильно поняли цель try catch или, может быть, у вас просто шаткий момент:

@Transactional(propagation = Propagation.REQUIRES_NEW)
def test2() {
  //you may be doing other stuff here
  //but now about to do some transaction work 
  //so lets wrap this method around a try catch
  try { 
    //this is happening
    def dummy = new Dummy(name: "test2")
    dummy.save()       
  } catch (Exception all) {  // or catch (Throwable all) {
     // if something went wrong in above save method
     //should be caught and runtime exception means roll back
     throw new RuntimeException("test2!" +all?.toString())
  }
}

Я надеюсь, что это объясняет, где вы ошиблись, но на самом деле вы хотите сделать все это в сервисе и выполнить часть try catch в контроллере -

поэтому вы выполняете свою транзакционную работу, и если что-то пойдет не так, вы можете захотеть выдать дополнительные исключения из службы, которые будет захватывать try catch в контроллере, и настроить его на откат.

Я сделал пример проекта несколько лет назад, надеюсь, это поможет

в любом случае, это чьи-то эксперименты, и на самом деле это не тот способ, которым вы бы занимались правильным кодированием, я имею в виду, что это довольно странный необычный способ делать что-то, и, короче говоря, он просто пытается заставить его генерировать исключение во время выполнения, поэтому вызывает откат . Я придерживаюсь своего предложения в ответе, что вы хотите сделать разовую попытку в контроллере. Это пытается зафиксировать как ошибки проверки объекта под рукой, так и сбои в сбое любой данной транзакционной работы службы. Что-то вроде этого, но, вероятно, потребуется гораздо больше работы, чтобы зафиксировать все конкретные проблемы и вернуться на исходную страницу с основными проблемами - теперь также откатив транзакцию.

person V H    schedule 16.02.2017
comment
Я ожидал, что прокси все равно распознает исключение. См. Тест 2 здесь: devhobbs.blogspot.de/2015/04/grailsgorm-transactions. .html (Результат теста 2: запись не записана. Откат исключения.) - person J.T.; 17.02.2017
comment
просто чтобы быть ясно, вы находитесь в службе? @Transactional(propagation = Propagation.REQUIRES_NEW) def test1() { находится на службе? а не контроллер, поскольку, если вы посмотрите на приведенный вами пример @Transactionalclass BookService { - person V H; 17.02.2017
comment
Я обновил свой ответ, так как мой комментарий о вашем примере и т. Д. Будет слишком длинным, проверьте обновленный ответ. - person V H; 17.02.2017
comment
Да, мои test1 и test2 находятся в службе. - person J.T.; 17.02.2017
comment
@Дж.Т. Я ожидал, что прокси все равно распознает исключение. - Прокси никогда не увидит исключения. Он никогда не покидает метод, потому что вы ловите его, а не перебрасываете. - person Jeff Scott Brown; 17.02.2017