2017-04-11 159 views
1

我需要一些幫助,試圖調試爲什麼我的春季啓動應用程序的事務管理不起作用。@事務註釋不按預期工作

基本思想是我有2個表,我想寫一些東西。當兩個表中的一個發生任何錯誤時,事務應該被回滾並且不應該寫入數據庫。

下面是代碼的簡化版本:

@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); 
     } 
    } 
} 

我執行的保存方法的類是被這樣定義彈簧數據JPA庫:

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

的線I註釋掉是強制性列。我這樣做是爲了強制執行ConstraintViolationException來測試在第二個表中保存某些內容時發生的異常。

會發生什麼是第一個實體保存成功,應該不會發生。我想弄明白爲什麼。

我的彈簧引導應用程序配置爲@EnableTransactionManagement以在我自己的服務中啓用@Transactional註釋(如此圖所示)。

我改變的日誌記錄級別org.springframework.transaction.interceptor來跟蹤,看看發生了什麼事情:

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] 

後,我不知道該記錄將是什麼樣子,如果交易管理工作正常,但它看起來它正在完成每筆交易。

有沒有人有一個想法,我可以嘗試接下來看看發生了什麼問題?

編輯:直到現在我一直在使用MySQL數據庫。我注意到,當我在H2數據庫上測試完全相同的代碼時,似乎回滾按預期工作。我看到的唯一區別是它引發了另一個特定於供應商的異常。

我試過明確設置上@Transactional註釋中的rollbackFor屬性,像這樣:

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

但即使這樣,也沒有引起回滾。

編輯:

這些都與JPA /休眠我的春天啓動設置:

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

請問您可以檢查'@ Transactional'註解的導入嗎?確保它不是從javax包中導入的,而是從spring包中導入的。 – galovics

+0

這是註釋的春天版本:org.springframework.transaction.annotation.Transactional – geoffreydv

+0

請問您可以包含'calculationRunRepository.save(run)'方法嗎?這可能是因爲你在這裏有不同的事務傳播。 – galovics

回答

0

我不知道你爲什麼在庫< OffloadedRun,字符串使用字符串爲您的ID類型>。您的OffloadedRun域具有String類型的ID?它應該與OffloadedRun域中您的id字段的類型匹配。確保案件。確認, 您能否請您發佈您的OffloadedRun域代碼?

0

您必須使用org.springframework.orm.hibernate4.HibernateTransactionManager。

您可能正在使用org.springframework.orm.jpa.JpaTransactionManager。