1. 程式人生 > >hibernate迴圈插入資料

hibernate迴圈插入資料

       在使用hibernate持久化資料時,經常會預見迴圈插入資料的問題。一個有趣的現象是,在迴圈插入資料的時候,只有第一條資料時真正插入到資料庫的,剩餘的都在對這條資料進行更新操作。

      例如如下程式碼:

<pre class="java" name="code">for(int i=0;i<j;i++){
    //do something
    xxDAO.save(dataToSave);
}

     上述程式碼本意是將該物件儲存J個,但是很遺憾,hibernate在持久化時不會在資料庫儲存J個物件。它只會插入一個,然後對該物件更新J-1次。其原因是hibernate在持久化的過程中主要是靠ID(主鍵)來識別物件的。當第一次儲存時,hibernate已經通過主鍵 生成策略產生了ID,並將其賦值給物件。雖然在後面我們還進行了J-1次插入,但實際上hibernate的session.save()和session.update()方法最後都是呼叫saveOrUpdate()方法的。當hibernate檢測到改物件(通過ID識別)已經持久化後,剩餘的都是對該物件的更新了。

    所以在需要迴圈初始化物件的時候,我們需要每次save的都是一個新的、並未持久化的物件。例如通過new關鍵字建立。但我在測試這個問題的時候犯了瞭如下的錯誤

<pre class="java" name="code">for(int i=0;i<j;i++){
    BeanToSave data=new BeanToSave();
    //beanToSave已經存在的一個bean實體物件
    data=beanToSave;
    xxDAO.save(data);
}

    上述程式碼看起來每次都new 了一個物件用於儲存,但實際上的效果更開頭的示例一樣,也只是插入一條資料,剩下的操作都將對該物件進行更新。則可以藉助C或者C++的指標來理解,就變得很簡單了。實際上我們每次儲存的仍然是beanToSave這個物件。只是此時data和beanToSave持有同一條引用。

   正確的應該這樣:

for(int i=0;i<j;i++){
    BeanToSave data=new BeanToSave();
    //beanToSave已經存在的一個bean實體物件
    data=Util.merge(beanToSave);
    xxDAO.save(data);
}

    其中的Util.merge()應該是一個類似於Mapping的函式,它能將beanToSave的屬性值傳遞給data(即相同class物件的屬性複製)。這樣我們在儲存時,才會插入J條資料。

    但是個人感覺,在採用Spring的DI注入時,主動new自定義物件,不是跟Spring的解耦思想相違背嗎?