2016-09-14 205 views
0

我使用Spring數據與Hibernate作爲JPA實現。爲什麼在執行saveAndFlush之前,hibernate再次加載實體?

在某個時候,我加載一輛車,操縱它並保存。使用Spring JPA-Repository的代碼如下所示:

@Entity @DynamicUpdate @DynamicInsert 
public class Car{ 
    @PostLoad 
    void postLoad(){ log.debug("post load"); } 

    @PrePersist @PreUpdate 
    void preSave(){ log.debug("prePersist/preUpdate"); } 

    /*..*/ 
} 

@Repository 
public interface CarRepository extends JpaRepository<Car, Integer>{} 

@Controller 
public CarController{ 
    public void businessLogic(){ 
     Car car = carRepo.findOne(1); // SELECT ... 
     log.debug("Car loaded"); 
     car.setColor("red"); 
     // ... 
     carRepo.saveAndFlush(car);  // UPDATE car SET ... <-- !!! 
    } 
} 

這適用於所有自動化測試和99%的生產。與事務日誌和SQL日誌是這樣的大多數時間:

SQL: select ... from Car ... 
Car: post load 
Car loaded 
Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush] 
Car: prePersist/preUpdate 
SQL: update Car set ... 
Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush] 

只有少數時候,Hibernate沒有一個SELECT 前右側的更新。

SQL: select ... from Car ... 
Car: post load 
Car loaded 
Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush] 
SQL: select ... from Car ... 
Car: post load 
Car: prePersist/preUpdate 
SQL: update Car set ... 
Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush] 

有人可以解釋第二次選擇的情況嗎?我無法看到它。

+0

不知道你的整個設置,但是如果Car有'子對象',那麼Hibernate可能會選擇檢查這些子對象是否已經存在於數據庫中,因此它不必保存它們(因爲它們是已經在那了)。 – Shadov

+0

其他代碼應該在一個服務,這將是事務性的,而不是在你的控制器。現在,您擁有2個(隱式)事務,而所有事務都應在單個事務中。除此之外,你應該(需要)做一個'saveAndFlush'只需一個'save'就足夠了。 –

回答

1

這是Hibernate做髒檢查。它重新加載實體以將其與您保存的任何更改進行比較。

有幾種方法可以降低其性能影響,例如使用版本控制:Java - JPA - @Version annotation或字節碼修改,以使髒檢查更高效。

+0

這也是我的預期。但大多數時候它不會從數據庫重新加載。當Hibernate沒有足夠的信息來處理這個請求時,是否有可能識別這些情況? – Marcel

+0

你的意思是編程?我想這個機制是在某個地方記錄的(在源代碼中,如果沒有其他的地方),但我不會開始編寫我自己的功能。 – Kayaman

+0

鏈接已死 – sloth

0

Hibernate在每次在同一事務中執行一些保存/刪除操作後都有SELECT語句時會進行髒檢查。髒檢查是爲了清除第1/2級緩存。大致上,Hibernate通過HashMap查找,包含緩存表的名稱,並與請求中使用的表進行比較。

相關問題