sql >> Database >  >> RDS >> Oracle

Rol A terug als B fout gaat. spring boot, jdbctemplate

@Transactional annotatie in de lente werkt door uw object in een proxy te wikkelen die op zijn beurt methoden omhult die zijn geannoteerd met @Transactional bij een transactie. Daarom werkt annotatie niet op privémethoden (zoals in uw voorbeeld) omdat privémethoden niet kunnen worden overgenomen => ze kunnen niet worden ingepakt (dit is niet waar als u declaratieve transacties met aspectj gebruikt, dan zijn de proxygerelateerde voorbehouden hieronder niet van toepassing).

Hier is een basisuitleg over hoe @Transactional lente magie werkt.

Je schreef:

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

Maar dit krijg je eigenlijk als je een boon injecteert:

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

Dit heeft beperkingen. Ze werken niet met @PostConstruct methoden omdat ze worden aangeroepen voordat het object wordt geproxyd. En zelfs als je alles correct hebt geconfigureerd, worden transacties alleen teruggedraaid op uitgeschakeld uitzonderingen standaard. Gebruik @Transactional(rollbackFor={CustomCheckedException.class}) als u terugdraait op een gecontroleerde uitzondering.

Nog een veelvoorkomend voorbehoud dat ik ken:

@Transactional methode werkt alleen als je het "van buitenaf" noemt, in het volgende voorbeeld b() zal niet worden verpakt in transactie:

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

   @Transactional
   public void b() {
   }
}

Het is ook omdat @Transactional werkt door uw object te proxyen. In het bovenstaande voorbeeld a() zal X.b() . aanroepen geen verbeterde "spring proxy"-methode b() dus er vindt geen transactie plaats. Als tijdelijke oplossing moet je b() . aanroepen van een andere boon.

Wanneer u een van deze waarschuwingen tegenkomt en geen voorgestelde oplossing kunt gebruiken (maak de methode niet-privé of bel b() van een andere boon) kunt u TransactionTemplate . gebruiken in plaats van declaratieve transacties:

public class A {
    @Autowired
    TransactionTemplate transactionTemplate;

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

...
} 

Bijwerken

Beantwoorden van OP bijgewerkte vraag met behulp van bovenstaande informatie.

Welke methode moet worden geannoteerd met @Transactional:changes()? databaseChanges()?

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

Zorg ervoor dat changes() wordt "van buitenaf" van een boon genoemd, niet van de klasse zelf en nadat de context is geïnstantieerd (dit is bijvoorbeeld niet afterPropertiesSet() of @PostConstruct geannoteerde methode). Begrijp dat spring rollback-transacties standaard alleen voor niet-aangevinkte uitzonderingen worden teruggedraaid (probeer specifieker te zijn in de lijst met rollbackVoor gecontroleerde uitzonderingen).



  1. Hoe fouten in sqlplus weer te geven

  2. Hoe te bestellen op maandnaam in SQLite

  3. Hoe beperk ik het aantal rijen dat wordt geretourneerd door een Oracle-query na het bestellen?

  4. Dagen aftrekken van een datum in SQLite