2016-05-13 9 views
0

Ich habe Methode, wo ich versuche, eine Entität zu ändern, auch in dieser Methode möchte ich Transaktionsinformationen speichern. Wenn eine Ausnahme aufgetreten ist, möchte ich die Sicherungseinheit zurücksetzen, möchte aber dennoch die Transaktion speichern. Also, wie ein Repository für Entität Transaktions aber Repository für Transaktionen nicht zu machen?Wie mache ich ein JPA-Repository Transaktional aber nicht ein anderes?

Es Code aus dem Repository

@Override 
@Transactional(noRollbackFor=NotEnoughAmountInAccountException.class) 
<T extends Transaction> T save(T transaction); 

aber es hilft nicht. Speichern der Transaktion im letzten Block.

UPDATE

Ich löste es durch AOP verwenden. Ich erstelle das Transaktionsobjekt in der Aspektberatung und speichere es hier aus der JPA-Transaktion.

+0

Bitte stellen Sie eine Frage, zeigen Sie uns Ausnahmen verfolgen ... –

+0

Ich habe Frage hinzugefügt. Es gibt keinen Stack-Trace, nur die Transaktion wird aufgrund eines Rollbacks nicht gespeichert. – VDanyliuk

+0

Sie können Repository-Klassen unverändert lassen und Servicemethoden mit unterschiedlichen Transaktionsverhalten verwenden, sodass beim Aufrufen der Methode andere Servicemethoden mit anderem Transaktionsverhalten aufgerufen werden (z. B. Propagation.REQUIRES_NEW). Auf diese Weise können Sie "transaction" speichern und im Falle einer ungeprüften Ausnahme oder mit der Ausnahme "NotEnoughAmountInAccountException" kann die äußere Transaktion zurückgesetzt werden, aber die innere Transaktion mit neuem Verhalten wird weiterhin ausgeführt. – Bunti

Antwort

0

ich es AOP unter Verwendung gelöst speichern. Ich erstelle das Transaktionsobjekt in der Aspektberatung und speichere es hier aus der JPA-Transaktion.

Es ist @Transactional Methode

@SaveTransaction 
@Transactional 
public synchronized Transaction move(@NonNull String accountName, @NonNull String destinationName, @NonNull BigDecimal amount, String comment) { 
    checkAmountIsPositive(amount); 

    Account donor = getAccount(accountName); 
    Account acceptor = getAccount(destinationName); 

    if (!isEnoughAmount(accountName, amount)) throw new NotEnoughAmountInAccountException(); 

    BigDecimal newDonorAmount = donor.getAmount().add(amount.negate()); 
    BigDecimal newAcceptorAmount = acceptor.getAmount().add(amount); 

    donor.setAmount(newDonorAmount); 
    acceptor.setAmount(newAcceptorAmount); 

    accountRepository.save(donor); 
    accountRepository.save(acceptor); 

    return null; 
} 

Und es ist Aspekt Beratung

@Around("@annotation(com.softjourn.coin.server.aop.annotations.SaveTransaction)") 
public Transaction saveTransaction(ProceedingJoinPoint joinPoint) throws Throwable { 
    Transaction transaction = prepareTransaction(joinPoint); 
    try { 
     joinPoint.proceed(); 
     transaction.setStatus(TransactionStatus.SUCCESS); 
     return transaction; 
    } catch (Throwable e) { 
     transaction.setStatus(TransactionStatus.FAILED); 
     transaction.setError(e.getLocalizedMessage()); 
     throw e; 
    } finally { 
     transactionRepository.save(transaction); 
    } 
} 

Auch wird es wichtig, um diese Beratung höher als die Reihenfolge der @Transactional so diese Beratung über Transaktion zu machen. @Order (100) in der Aspektklasse einstellen. Standardmäßig ist die Reihenfolge kleiner und befindet sich unter Transaktion.

0

Tun Sie es in einem neuen @Transactional

@Transactional(propagation=Propagation.REQUIRES_NEW) 
<T extends Transaction> T save(T transaction); 

Dies wird Ihr transaction Element, auch wenn die anderen @Transactional wird zurückgerollt

+1

Ich habe das versucht, aber es funktioniert nicht für mich. – VDanyliuk

+0

vielleicht liegt es daran, dass Sie das Standard 'save' von spring-data überschreiben, was' @ Transactional' ist ... versuchen Sie es in einer benutzerdefinierten Methode, so etwas wie eine Methode mit dem Namen 'saveTransaction (T Transaktion)' .. Es sollte funktionieren (natürlich müssen Sie diese benutzerdefinierte Methode implementieren) – Pras

+0

Es funktioniert auch nicht. Wie ich es verstehe Spring erstellt Proxy-Methoden nur für öffentliche Methoden, so @Transactional auf private Methode funktioniert nicht. Ich möchte es nicht öffentlich machen, weil jemand es anrufen kann, ohne Transaktionen zu speichern. – VDanyliuk