2017-04-11 4 views
1

Ich brauche Hilfe beim Debuggen, warum die Transaktionsverwaltung meiner Spring-Boot-App nicht funktioniert.@Transactional Annotation nicht wie erwartet funktioniert

Die Grundidee ist, dass ich 2 Tabellen habe, in die ich etwas schreiben möchte. Wenn irgendetwas in einer der 2 Tabellen schief geht, sollte die Transaktion zurückgesetzt werden und nichts sollte in die Datenbank geschrieben werden.

Hier ist eine vereinfachte Version des Codes:

@Transactional 
public void archiveTask(String taskId) { 

    OffloadedRun run = new OffloadedRun(); 
    run.setStartDateTime(LocalDateTime.now()); 
    calculationRunRepository.save(run); 

    List<SingleContractCalculationResults> activeResults = contractCalculationResultAccessService.get(taskId); 

    for (SingleContractCalculationResults result : example) { 
     for (Map.Entry<String, ContractResults> entry : result.getResultsPerScenario().entrySet()) { 
      String scenario = entry.getKey(); 
      ContractResults results = entry.getValue(); 

      OffloadedCalculationResult offloadedCalculationResult = new OffloadedCalculationResult(); 

//    offloadedCalculationResult.setOffloadedRun(run); 
      offloadedCalculationResult.setContractId(result.getContractId()); 
      calculationResultRepository.save(offloadedCalculationResult); 
     } 
    } 
} 

Die Klassen, die ich die auf Spring Data JPA Repositories sind speichern Methoden ausführen, die wie folgt definiert sind:

public interface CalculationRunRepository extends JpaRepository<OffloadedRun, String> { 
} 

der Linie I Auskommentiert ist eine obligatorische Spalte. Ich tue dies, um eine ConstraintViolationException zu erzwingen, um zu testen, was bei einer Ausnahme passiert, wenn etwas in der zweiten Tabelle gespeichert wird.

Was passiert ist, dass die erste Entität erfolgreich gespeichert wurde, was nicht passiert sein sollte. Ich versuche herauszufinden, warum das so ist.

Meine Spring Boot-Anwendung ist mit @EnableTransactionManagement konfiguriert, um die @Transactional Anmerkungen in meinen eigenen Diensten (wie diesem) zu aktivieren.

änderte ich die Protokollstufe für org.springframework.transaction.interceptor zu sehen, zu verfolgen, was los ist:

o.s.t.i.TransactionInterceptor   : Getting transaction for [be.sodemo.calculator.offloading.TaskArchiverImpl.archiveTask] 
o.s.t.i.TransactionInterceptor   : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 
o.s.t.i.TransactionInterceptor   : Completing transaction for [be.sodemo.calculator.offloading.TaskArchiverImpl.archiveTask] 

o.h.e.j.s.SqlExceptionHelper    : SQL Error: 1048, SQLState: 23000 
o.h.e.j.s.SqlExceptionHelper    : Column 'run_id' cannot be null 
o.h.e.j.b.i.AbstractBatchImpl   : HHH000010: On release of batch it still contained JDBC statements 
o.a.c.c.C.[.[.[.[dispatcherServlet]  : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause 

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'run_id' cannot be null 
    at sun.reflect.GeneratedConstructorAccessor2599.newInstance(Unknown Source) ~[?:?] 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java) ~[?:1.8.0_102] 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[?:1.8.0_102] 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.40.jar:5.1.40] 

Nach diesen

Ich bin mir nicht sicher, was die Protokollierung aussehen würde, wenn das Transaktionsmanagement funktioniert, aber es sieht so aus, als würde es jede Transaktion abschließen.

Hat jemand eine Idee, was ich als nächstes versuchen kann, um zu sehen, was schief läuft?

Edit: Bis jetzt habe ich eine MySQL-Datenbank verwendet. Ich habe festgestellt, dass, als ich genau diesen Code in einer H2-Datenbank getestet habe, es so aussieht, als ob der Rollback wie vorgesehen funktioniert. Der einzige Unterschied, den ich sehe, ist, dass eine andere herstellerspezifische Ausnahme ausgelöst wird.

Ich habe versucht, explizit das rollbackFor Attribut auf der @Transactional Anmerkung Einstellung wie folgt:

@Transactional(rollbackFor = {Exception.class, MySQLIntegrityConstraintViolationException.class})

Aber auch das kein Rollback verursacht hat.

Edit:

Diese meine Feder Boot-Einstellungen beziehen sich auf JPA/Hibernate:

spring: 
    jpa: 
    hibernate: 
     ddl-auto: none 
     dialect: org.hibernate.dialect.MySQL5Dialect 
    database: mysql 
    properties: 
     hibernate: 
     order_inserts: true 
     jdbc: 
      batch_size: 50 
    datasource: 
    url: jdbc:mysql://localhost/local-test-db 
    driver-class-name: com.mysql.jdbc.Driver 
+2

Könnten Sie bitte den Import für die Annotation "@Transactional" überprüfen? Stellen Sie sicher, dass es nicht aus den Javax-Paketen importiert wird, sondern aus den Spring-Paketen. – galovics

+0

Es ist die Frühlingsversion der Anmerkung: org.springframework.transaction.annotation.Transactional – geoffreydv

+0

Könnten Sie bitte die Methode 'calculationRunRepository.save (run)' '? Möglicherweise haben Sie hier eine andere Transaktionsfortpflanzung. – galovics

Antwort

0

Ich bin nicht sicher, warum Sie String für Ihre ID-Typ in Repository < OffloadedRun, String verwenden>. Ihre OffloadedRun-Domain hat eine ID mit String-Typ? Es sollte mit dem Typ Ihres ID-Felds in der OffloadedRun-Domäne übereinstimmen. Achte auf den Fall. Um zu bestätigen, Könnten Sie bitte Ihren OffloadedRun-Domänencode auch posten?

0

Sie müssen org.springframework.orm.hibernate4.HibernateTransactionManager verwenden.

Sie verwenden möglicherweise org.springframework.orm.jpa.JpaTransactionManager.

Verwandte Themen