sql >> Database teknologi >  >> RDS >> Oracle

Rul A tilbage, hvis B går galt. fjederstøvle, jdbctemplate

@Transactional annotation in spring fungerer ved at pakke dit objekt ind i en proxy, som igen ombryder metoder, der er kommenteret med @Transactional i en transaktion. På grund af den annotering vil den ikke virke på private metoder (som i dit eksempel), fordi private metoder ikke kan nedarves => de kan ikke ombrydes (dette er ikke sandt, hvis du bruger deklarative transaktioner med aspectj, så gælder proxy-relaterede forbehold nedenfor ikke).

Her er en grundlæggende forklaring på hvordan @Transactional forårets magi virker.

Du skrev:

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

Men dette er, hvad du faktisk får, når du injicerer en bønne:

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
       }
   }
} 

Dette har begrænsninger. De virker ikke med @PostConstruct metoder, fordi de kaldes før objektet er proxy. Og selvom du har konfigureret alt korrekt, bliver transaktioner kun rullet tilbage ved ikke markeret undtagelser som standard. Brug @Transactional(rollbackFor={CustomCheckedException.class}) hvis du har brug for tilbagerulning af en eller anden markeret undtagelse.

En anden ofte stødt advarsel, jeg kender:

@Transactional metoden vil kun fungere, hvis du kalder den "udefra", i følgende eksempel b() vil ikke blive pakket ind i transaktionen:

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

   @Transactional
   public void b() {
   }
}

Det er også fordi @Transactional fungerer ved at proxygive dit objekt. I eksemplet ovenfor a() kalder X.b() ikke en forbedret "spring proxy"-metode b() så der vil ikke være nogen transaktion. Som en løsning skal du kalde b() fra en anden bønne.

Når du stødte på nogen af ​​disse advarsler og ikke kan bruge en foreslået løsning (gør metoden til ikke-privat, eller kald b() fra en anden bønne) kan du bruge TransactionTemplate i stedet for deklarative transaktioner:

public class A {
    @Autowired
    TransactionTemplate transactionTemplate;

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

...
} 

Opdater

Besvarelse af OP opdateret spørgsmål ved hjælp af info ovenfor.

Hvilken metode skal annoteres med @Transactional:changes()? databaseChanges()?

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

Sørg for at changes() kaldes "udefra" af en bønne, ikke fra selve klassen og efter konteksten blev instansieret (f.eks. er dette ikke afterPropertiesSet() eller @PostConstruct annoteret metode). Forstå, at foråret rollback-transaktion kun for umarkerede undtagelser som standard (prøv at være mere specifik i rollbackFor checked undtagelsesliste).



  1. Brug af Geekbench 3.2 til at teste store databaseservere

  2. 2 måder at returnere rækker, der kun indeholder ikke-alfanumeriske tegn i MySQL

  3. Indlæs CSV-data i MySQL i Python

  4. ClusterControl - Advanced Backup Management - mariabackup del I