Hibernate的SQL執行順序引起的血案

問題起源於代碼中對某個對象的處理邏輯,當發現該對象的某些屬性變化時,先將原數據刪除,再插入一個新對象,因爲使用了Spring+Hibernate的組合,很容易寫出以下代碼: java

//從數據庫中讀取原數據
Role entity = hibernateTemplate.load(ID);
//將數據複製到新對象上
Role newEntity = new Role();
BeanCopier.copy(entity, newEntity);
//刪除原數據
hibernateTemplate.delete(entity);
//保存新數據
hibernateTemplate.save(entity);
然而這段代碼在執行時卻失敗了,程序拋出:DataIntegrityViolationException異常,日誌顯示以下錯誤:
SQL Error: 1062, SQLState: 23000
Duplicate entry 'demo' for key 'IDX_ROLE_NAME'
即數據插入數據庫時失敗了,緣由是觸發了惟一性約束。經反覆覈實,數據庫中數據沒有問題,不是其餘數據致使的,從代碼邏輯上講,這段代碼先刪後插也沒有任何問題,在一個事務當中也沒有什麼髒讀的問題, 這就搞笑了,問題到底出在哪呢???
打開Hibernate的SQL輸出,還原最真實的SQL語句,終於找到了答案,輸入日誌以下:
Hibernate: 
    /* insert com.litt.cidp.system.po.Role
        */ insert 
        into
            role
            (ROLE_NAME, STATUS, REMARK) 
        values
            (?, ?, ?)
Hibernate: 
    /* update
        com.litt.cidp.system.po.Role */ update
            role 
        set
            ROLE_NAME=?,
            STATUS=?,
            REMARK=? 
        where
            ROLE_ID=?
Hibernate: 
    /* delete com.litt.cidp.system.po.Role */ delete 
        from
            role 
        where
            ROLE_ID=?

Hibernate在最終執行SQL語句時,竟然是按INSERT, UPDATE, DELETE的順序執行的,而非按照代碼順序執行!What the F!查閱了相關資料,說是Hibernate爲了性能優化,對象操做都是放在緩存裏而沒有當即執行數據庫操做直到commit操做,爲的是利用batch操做提升數據庫操做性能;老天,那業務邏輯怎麼辦?同理,在一個事務中混用Hibernate和JDBC操做,將致使數據不一致問題sql

解決方案:在須要同步的地方(即按照INSERT, UPDATE, DELETE順序有可能產生問題的時候;混用JDBC操做的時候),執行session.flush()方案,該方法將緩存中的數據請求當即轉換爲數據庫操做並執行。 數據庫

相關文章
相關標籤/搜索