問題起源於代碼中對某個對象的處理邏輯,當發現該對象的某些屬性變化時,先將原數據刪除,再插入一個新對象,因爲使用了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: /* 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()方案,該方法將緩存中的數據請求當即轉換爲數據庫操做並執行。 數據庫