[java] JPA-Transaktion konnte nicht bestätigt werden: Transaktion wurde als rollbackOnly markiert



1 Answers

JPA-Transaktion konnte nicht bestätigt werden: Transaktion wurde als rollbackOnly markiert

Diese Ausnahme tritt auf, wenn Sie verschachtelte Methoden / Dienste aufrufen, die auch als @Transactional gekennzeichnet @Transactional . JB Nizet erklärte den Mechanismus im Detail. Ich möchte einige Szenarien hinzufügen , wenn es passiert, und einige Möglichkeiten, dies zu vermeiden .

Angenommen, wir haben zwei Spring-Services: Service1 und Service2 . Aus unserem Programm rufen wir Service1.method1() das wiederum Service2.method2() aufruft:

class Service1 {
    @Transactional
    public void method1() {
        try {
            ...
            service2.method2();
            ...
        } catch (Exception e) {
            ...
        }
    }
}

class Service2 {
    @Transactional
    public void method2() {
        ...
        throw new SomeException();
        ...
    }
}

SomeException ist SomeException (erweitert RuntimeException), sofern nicht anders angegeben.

Szenarien:

  1. Die Transaktion wurde zum Zurücksetzen durch eine Ausnahme markiert, die aus method2 . Dies ist unser Standardfall, der von JB Nizet erklärt wurde.

  2. Die Annotation von method2 als @Transactional(readOnly = true) markiert die Transaktion immer noch für Rollback (Ausnahme beim Verlassen von method1 ).

  3. Das method1 und method2 als @Transactional(readOnly = true) markiert immer noch die Transaktion für Rollback (Ausnahme beim Verlassen von method1 ).

  4. Die Annotation von method2 mit @Transactional(noRollbackFor = SomeException) verhindert das Markieren einer Transaktion für Rollback ( keine Ausnahme beim Verlassen von method1 ).

  5. Angenommen, method2 gehört zu Service1 . Der Aufruf von method1 erfolgt nicht über den Spring-Proxy, dh Spring kennt SomeException nicht, die aus SomeException geworfen wird. Die Transaktion ist in diesem Fall nicht zum Zurücksetzen markiert .

  6. Angenommen, method2 ist nicht mit @Transactional . Der Aufruf von method1 durchläuft den Spring-Proxy, aber Spring berücksichtigt keine ausgelösten Exceptions. Die Transaktion ist in diesem Fall nicht zum Zurücksetzen markiert .

  7. Die Annotation von method2 mit @Transactional(propagation = Propagation.REQUIRES_NEW) method2 , eine neue Transaktion zu starten. Diese zweite Transaktion wird beim Beenden von method2 für den Rollback method2 aber die ursprüngliche Transaktion ist in diesem Fall nicht betroffen ( keine Ausnahme beim Verlassen von method1 ).

  8. SomeException ist (RuntimeException nicht erweitert wird), kennzeichnet Spring standardmäßig keine Transaktion für Rollback, wenn abgefangene Ausnahmen abgefangen werden ( keine Ausnahme beim Verlassen von method1 ).

Sehen Sie alle in diesem Geiste getesteten Szenarien .

Question

Ich verwende Spring und Hibernate in einer der Anwendungen, an denen ich arbeite, und ich habe ein Problem mit der Abwicklung von Transaktionen.

Ich habe eine Dienstklasse, die einige Entitäten aus der Datenbank lädt, einige ihrer Werte ändert und dann (wenn alles gültig ist) diese Änderungen an die Datenbank festschreibt. Wenn die neuen Werte ungültig sind (was ich erst überprüfen kann, nachdem ich sie eingestellt habe), möchte ich die Änderungen nicht beibehalten. Um zu verhindern, dass Spring / Hibernate die Änderungen speichert, werfe ich eine Ausnahme in die Methode. Dies führt jedoch zu folgendem Fehler:

Could not commit JPA transaction: Transaction marked as rollbackOnly

Und das ist der Service:

@Service
class MyService {

  @Transactional(rollbackFor = MyCustomException.class)
  public void doSth() throws MyCustomException {
    //load entities from database
    //modify some of their values
    //check if they are valid
    if(invalid) { //if they arent valid, throw an exception
      throw new MyCustomException();
    }

  }
}

Und so rufe ich es auf:

class ServiceUser {
  @Autowired
  private MyService myService;

  public void method() {
    try {
      myService.doSth();
    } catch (MyCustomException e) {
      // ...
    }        
  }
}

Was ich erwarten würde: Keine Änderungen an der Datenbank und keine für den Benutzer sichtbare Ausnahme.

Was passiert: Keine Änderungen an der Datenbank, aber die App stürzt ab mit:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction;
nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly

Es setzt die Transaktion korrekt auf rollbackOnly, aber warum stürzt das Rollback mit einer Ausnahme ab?




Speichern Sie zuerst das Unterobjekt und rufen Sie dann die Methode zum Speichern des Endspeichers auf.

@PostMapping("/save")
    public String save(@ModelAttribute("shortcode") @Valid Shortcode shortcode, BindingResult result) {
        Shortcode existingShortcode = shortcodeService.findByShortcode(shortcode.getShortcode());
        if (existingShortcode != null) {
            result.rejectValue(shortcode.getShortcode(), "This shortode is already created.");
        }
        if (result.hasErrors()) {
            return "redirect:/shortcode/create";
        }
        **shortcode.setUser(userService.findByUsername(shortcode.getUser().getUsername()));**
        shortcodeService.save(shortcode);
        return "redirect:/shortcode/create?success";
    }





Related