Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Cofnij A, jeśli B pójdzie nie tak. wiosna boot, jdbctemplate

@Transactional adnotacja na wiosnę działa poprzez owinięcie obiektu w proxy, który z kolei zawija metody z adnotacjami @Transactional w transakcji. Z tego powodu adnotacja nie będzie działać w przypadku metod prywatnych (jak w Twoim przykładzie), ponieważ metody prywatne nie mogą być dziedziczone => nie mogą być opakowane (nie jest to prawdą, jeśli używasz transakcji deklaratywnych z aspektem, wówczas poniższe zastrzeżenia dotyczące proxy nie mają zastosowania).

Oto podstawowe wyjaśnienie, w jaki sposób @Transactional wiosenna magia działa.

Napisałeś:

class A {
    @Transactional
    public void method() {
    }
}

Ale to właśnie otrzymujesz po wstrzyknięciu fasoli:

class ProxiedA extends A {
   private final A a;

   public ProxiedA(A a) {
       this.a = a;
   }

   @Override
   public void method() {
       try {
           // open transaction ...
           a.method();
           // commit transaction
       } catch (RuntimeException e) {
           // rollback transaction
       } catch (Exception e) {
           // commit transaction
       }
   }
} 

To ma ograniczenia. Nie działają z @PostConstruct metody, ponieważ są wywoływane przed serwerem proxy. A nawet jeśli wszystko skonfigurowałeś poprawnie, transakcje są cofane tylko po niezaznaczeniu wyjątki domyślnie. Użyj @Transactional(rollbackFor={CustomCheckedException.class}) jeśli potrzebujesz wycofania jakiegoś zaznaczonego wyjątku.

Inne często spotykane zastrzeżenie, które znam:

@Transactional metoda zadziała tylko jeśli nazwiesz ją "z zewnątrz", w poniższym przykładzie b() nie zostaną objęte transakcją:

class X {
   public void a() {
      b();
   }

   @Transactional
   public void b() {
   }
}

Dzieje się tak również dlatego, że @Transactional działa poprzez proxy twojego obiektu. W powyższym przykładzie a() wywoła X.b() nie ulepszona metoda "wiosenne proxy" b() więc nie będzie transakcji. Jako obejście musisz wywołać b() z innego ziarna.

Gdy napotkasz którekolwiek z tych ostrzeżeń i nie możesz użyć sugerowanego obejścia (ustaw metodę jako nieprywatną lub wywołaj b() z innego ziarna) możesz użyć TransactionTemplate zamiast transakcji deklaratywnych:

public class A {
    @Autowired
    TransactionTemplate transactionTemplate;

    public void method() {
        transactionTemplate.execute(status -> {
            A();
            B();
            return null;
        });
    }

...
} 

Aktualizacja

Odpowiadając na zaktualizowane pytanie OP, korzystając z powyższych informacji.

Którą metodę należy opisać za pomocą @Transactional:changes()? DatabaseChanges()?

@Transactional(rollbackFor={Exception.class})
public void changes() throws Exception {
    someLogicBefore();
    databaseChanges();
    someLogicAfter();
}

Upewnij się, że changes() jest wywoływana „z zewnątrz” ziarna, a nie z samej klasy i po utworzeniu instancji kontekstu (np. nie jest to afterPropertiesSet() lub @PostConstruct metoda z adnotacjami). Zrozum, że domyślnie wycofuje ona transakcję tylko dla niesprawdzonych wyjątków (spróbuj być bardziej szczegółowy w liście cofnięć dla zaznaczonych wyjątków).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Usuń nagłówek kolumny do wyjściowego pliku tekstowego

  2. Zapytanie Oracle do pobrania nazw kolumn

  3. Jak wykonać plik skryptu .SQL za pomocą c#

  4. Pobierz listę wszystkich tabel w Oracle?

  5. Błąd 404 nie został znaleziony w EM 12c