sql >> Databasteknik >  >> RDS >> Oracle

Rulla tillbaka A om B går fel. fjäderstövel, jdbctemplate

@Transactional annotation in spring fungerar genom att ditt objekt lindas in i en proxy som i sin tur omsluter metoder som är kommenterade med @Transactional i en transaktion. På grund av den kommer anteckningen inte att fungera på privata metoder (som i ditt exempel) eftersom privata metoder inte kan ärvas => de kan inte lindas (detta är inte sant om du använder deklarativa transaktioner med aspectj, då gäller inte proxyrelaterade varningar nedan).

Här är en grundläggande förklaring av hur @Transactional vårens magi fungerar.

Du skrev:

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

Men det här är vad du faktiskt får när du injicerar en böna:

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

Detta har begränsningar. De fungerar inte med @PostConstruct metoder eftersom de anropas innan objektet proxias. Och även om du har konfigurerat allt korrekt, återställs transaktioner endast vid avmarkerad undantag som standard. Använd @Transactional(rollbackFor={CustomCheckedException.class}) om du behöver återställa något markerat undantag.

En annan varning som jag ofta stöter på vet jag:

@Transactional Metoden fungerar bara om du kallar den "från utsidan", i följande exempel b() kommer inte att inkluderas i transaktionen:

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

   @Transactional
   public void b() {
   }
}

Det beror också på att @Transactional fungerar genom att proxyservera ditt objekt. I exemplet ovan a() anropar X.b() inte en förbättrad "spring proxy"-metod b() så det blir ingen transaktion. Som en lösning måste du anropa b() från en annan böna.

När du stött på någon av dessa varningar och inte kan använda en föreslagen lösning (gör metoden icke-privat eller anrop b() från en annan böna) kan du använda TransactionTemplate istället för deklarativa transaktioner:

public class A {
    @Autowired
    TransactionTemplate transactionTemplate;

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

...
} 

Uppdatera

Svarar på OP uppdaterad fråga med hjälp av info ovan.

Vilken metod ska noteras med @Transactional:changes()? databaseChanges()?

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

Se till att changes() kallas "från utsidan" av en böna, inte från själva klassen och efter att sammanhanget instansierades (t.ex. är det inte afterPropertiesSet() eller @PostConstruct annoterad metod). Förstå att våren återställer transaktionen endast för omarkerade undantag som standard (försök att vara mer specifik i återställningslistan för markerade undantag).



  1. INFOGA med 10 miljoner frågor under 10 minuter i Oracle?

  2. varför jag misslyckas med att skapa den här tabellen på Android SQLite?

  3. Operand bör innehålla 1 kolumn - MySQL NOT IN

  4. Hur ringer man lagrad procedur i en vy?