2017-02-17 19 views
12

爲了管理MySql數據庫,我使用Spring Boot(1.4.4.REALEASE)和Spring Data。我有以下情況:在一個事務中執行的Spring本地查詢取得了過時的值

  1. 我們更新了使用RevisionService在一臺設備上執行的一個修訂。
  2. RevisionService保存修訂並調用EquipmentService來更新設備狀態。
  3. updateEquipmentStatus會對Db存儲過程進行調用,以便完全評估設備及其修訂版並更新字段。

我試過一些選項,但沒有達到獲取設備的更新狀態。 updateEquipmentStatus方法不斷寫入設備的先前狀態(不考慮當前修訂存儲在事務中)。該代碼是這樣寫的:

RevisionService

@Service 
public class RevisionService{ 

    @org.springframework.transaction.annotation.Transactional 
    public Long saveRevision(Revision rev){ 
     //save the revision using JPA-Hibernate 
     repo.save(rev); 
     equipmentService.updateEquipmentStatus(idEquipment); 
    } 
} 

EquipmentService

@Service 
public class EquipmentService{ 

    @org.springframework.transaction.annotation.Transactional 
    public Long updateEquipmentStatus(Long idEquipment){ 
     repo.updateEquipmentStatus(idEquipment); 
    } 
} 

EquipmentRepo

@Repository 
public interface EquipmentRepo extends CrudRepository<Equipment, Long> { 

    @Modifying 
    @Procedure(name = "pupdate_equipment_status") 
    void updateEquipmentStatus(@Param("id_param") Long idEquipment); 

} 

據我所知,由於這兩種方法都使用Spring的事務註釋,所以updateEquipmentStatus方法應該在當前事務的範圍內執行。我還嘗試使用的@Transactional註釋的不同選項,例如@Transactional(isolation=Isolation.READ_UNCOMMITTED)(這不應該是必需的,因爲我使用相同的事務)和@Transactional(propagation=Propagation.REQUIRES_NEW),但不會考慮當前狀態。這是我的存儲過程是如何保存到MySQL數據庫:

CREATE DEFINER=`root`@`localhost` PROCEDURE `pupdate_equipment_status`(IN `id_param` INT) 
    LANGUAGE SQL 
    NOT DETERMINISTIC 
    MODIFIES SQL DATA 
    SQL SECURITY DEFINER 
    COMMENT '' 
BEGIN 

/*Performs the update considering tequipment and trevision*/ 
/*to calculate the equipment status, no transaction is managed here*/ 

END 

我也想澄清的是,如果我執行在設備本身(這隻會影響精裝配件)做一些修改,狀態得到了適當的更新。 InnoDb是用於所有表格的引擎。


UPDATE

只是改變了回購方式使用nativeQuery來代替,而同樣的問題持續發生,所以數據庫程序參與應該被丟棄:

@Modifying 
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))") 
void updateEquipmentStatus(@Param("id_param") Long idEquipment); 

UPDATE2

已經完成更多的測試,並增加了日誌與方法TransactionSynchronizationManager.getCurrentTransactionName(),這就是具體問題:

  • 變化的設備服務進行適當的更新功能(採摘當東西精裝配件的變化,在狀態精確計算配件)。
  • 修改服務(trevision)中所做的更改會導致tequipment中的過期值(如果Spring使用REQUIRES_NEW在不同的事務中執行此操作,則無關緊要)。當在establishEquipmentStatus中使用REQUIRES_NEW時,Spring似乎會正確創建一個新的事務,因爲當前事務名稱發生更改,但本機查詢沒有最新值(因爲事務沒有被提交之前?)。還嘗試從establishEquipmentStatus中刪除@Transactional,以便使用相同的事務,但問題不斷髮生。
  • 我想突出顯示查詢用於更新設備狀態具有case expression與多個子查詢使用trevision。

回答

0

添加以下代碼修復它(編程刷新交易狀態數據庫):

@Service 
public class EquipmentService{ 

    @PersistenceContext 
    private EntityManager entityManager; 

    @org.springframework.transaction.annotation.Transactional 
    public Long updateEquipmentStatus(Long idEquipment){ 
     entityManager.flush(); 
     repo.updateEquipmentStatus(idEquipment); 
    } 
} 

不過這將是偉大的發現以聲明方式來做到這一點..

0

更改爲未提交讀取是正確的想法,但在調用存儲過程之前還需要刷新entitymanager。看到這個線程:

How to make the queries in a stored procedure aware of the Spring Transaction?

個人而言,我會做這一切在春季,除非你是絕對被迫使用存儲過程。

+0

嗨,對不起延時。實際上,問題不是存儲過程特定的,但似乎它涉及許多涉及同一事務的表(它需要舊錶值)。或多或少,這就是執行流程:1.使用Hibernate更新修訂版。 2.執行'updateEquipmentStatus'方法,該方法觸發修改的本地查詢(此查詢使用了一些涉及步驟1的數據,這些數據已過時)。 –

相關問題