hibernate save,update,saveorupdate方法有什么區別


save肯定是添加的時候用,update修改時候用,saveorupdate是添加或修改,如果真是這樣save和update的存在就沒意義了,我們直接saveorupdate就行了。
save在添加用的時候  不會出現索引機制(即遍歷目錄  效率最高)
update在修改時候要遍歷 不存在則會異常
saveorupdate是優先遍歷 如果不存在則創建(效率最低)
merge和saveOrUpdate方法區別在於:merge方法是把我們提供的對象轉變為托管狀態的對象;而saveOrUpdate則是把我們提供的對象變成一個持久化對象;
說的通俗一點就是:saveOrUpdate后的對象會納入session的管理,對象的狀態會跟數據庫同步,再次查詢該對象會直接從session中取,merge后的對 
象不會納入session的管理,再次查詢該對象還是會從數據庫中取。

 Session的save()方法使一個臨時對象轉變為持久化對象。例如以下代碼保存一個Customer對象:

        Customer customer = new Customer();

        customer.setId(new Long(9)); // 為Customer臨時對象設置OID是無效的

        customer.setName("Tom");

        Session session = sessionFactory.openSession();

        Transaction tx = session.beginTransaction();

        session.save(customer);

        session.close();

    Session的save()方法完成以下的操作:

    (1)把Customer對象加入到緩存中,使它變為持久化對象。

    (2)選用映射文件指定的標識符生成器為持久化對象分配惟一的OID。Customer.hbm.xml文件中<id>元素的<generator>子元素指定標識符生成器:

        <id name="id" column="ID">

            <generator class="increment"/>

        </id>

    以上程序試圖通過setId()方法為Customer臨時對象設置OID是無效的。假如起初CUSTOMERS表中沒有記錄,那么執行完save()方法后,Customer對象的ID為1。如果希望由程序來為Customer對象指定OID,可以調用save()的另一個重載方法:

        save(customer, new Long(9));

    以上save()方法的第二參數顯示指定Customer對象的OID。這種形式的save()方法不推薦使用,尤其在使用代理主鍵的場合,不應該由程序為持久化對象指定OID。

    (3)計划執行一個insert語句,把Customer對象當前的屬性值組裝到insert語句中:

        insert into CUSTOMERS(ID, NAME, ......) values(1, 'Tom', ......);

    值得注意的是,save()方法並不立即執行SQL insert語句。只有當Session清理緩存時,才會執行SQL insert語句。如果在save()方法之后,又修改了持久化對象的屬性,這會使得Session在清理緩存時,額外執行SQL update語句。以下兩段代碼盡管都能完成相同的功能,但是左邊代碼僅執行一條SQL insert語句,而右邊代碼執行一條SQL insert和一條SQL update語句。左邊代碼減少了操作數據庫的次數,具有更好的運行性能。

        Customer customer = new Customer();         Customer customer = new Customer();

        // 先設置Customer對象的屬性,再保存它       session.save(customer);

        customer.setName("Tom");                    // 先保存Customer對象,再修改它的屬性

        session.save(customer);                    customer.setName("Tom");

        transaction.commit();                      transaction.commit();

    Hibernate通過持久化對象的OID來維持它和數據庫相關記錄的對應關系。當Customer對象處於持久化狀態時,不允許程序隨意修改它的OID,例如:

        Customer customer = new Customer();

        session.save(customer);

        customer.setId(new Long(100)); // 拋出HibernateException

        transaction.commit();

    以上代碼會導致Session在清理緩存時拋出異常。

 


Hibernate <wbr>Session的save()方法無論Java對象處於臨時狀態、持久化狀態還是游離狀態,應用程序都不應該修改它的OID。因此,比較安全的做法是,在定義持久化類時,把它的setId()方法高為private類型,禁止外部程序訪問該方法。


 

    Session的save()方法是用來持久化一個臨時對象的。在應用程序中不應該把持久化對象或游離對象傳給save()方法。例如以下代碼兩次調用了Session的save()方法,第二次傳給save()方法的Customer對角處於持久化狀態,這步操作其它是多余的:

        Customer customer = new Customer();

        session.save(customer);

        customer.setName("Tom");

        session.save(customer); // 這步操作是多余的

       transaction.commit();

    在例如以下代碼把Customer游離對象傳給session2的save()方法,session2會把它當做臨時對象處理,再次向數據庫中插入一條Customer記錄:

        Customer customer = new Customer();

        customer.setName("Tom");

        Session session1 = sessionFactory.openSession();

        Transaction tx1 = session1.beginTransaction();

        session1.save(customer); // 此時Customer對象的ID變為1

        tx1.commit();

        session1.close(); // 此時Customer對象變為游離對象

        Session session2 = sessionFactory.openSession();

        Transaction tx2 = session2.beginTransaction();

        session2.save(cutomer); // 此時Customer對象的ID變為2

        tx2.commit();

        session2.close();

    盡管以上程序代碼能正常運行,但是會導致CUSTOMERS表中有兩條代表相同業務實體的記錄,因此不符合業務邏輯。

 

hibernate提供了saveOrUpdate的方法來進行數據庫的操作。hibernate會根據對象的狀態決定是insert還是update,
其根本是通過xml文件中unsaved-value來確定的。如果設置null,系統會根據傳入的對象的id的值判斷,如果是null,
則表示對象不存在,那么insert;如果不是Null,則表示已經存在,那么update.如果設置為none,那么表示對象不存在,
會始終調用insert;如果設置為any,那么表示對象始終存在,會始終調用update

 
        


    數據庫表主鍵的知識點:
    Generator 為每個 POJO 的實例提供唯一標識。一般情況,我們使用“native”。
class 表示采用由生成器接口net.sf.hibernate.id.IdentifierGenerator 實現的某個實例,其中包括:

 
        

   “assigned” 主鍵由外部程序負責生成,在 save() 之前指定一個。

 
        

   “hilo” 通過hi/lo 算法實現的主鍵生成機制,需要額外的數據庫表或字段提供高位值來源。

 
        

   “seqhilo”與hilo 類似,通過hi/lo 算法實現的主鍵生成機制,需要數據庫中的 Sequence,
            適用於支持 Sequence 的數據庫,如Oracle。

 
        

   “increment”主鍵按數值順序遞增。此方式的實現機制為在當前應用實例中維持一個變量,以保存着當前的最大值,
            之后每次需要生成主鍵的時候將此值加1作為主鍵。這種方式可能產生的問題是:不能在集群下使用。

 
        

   “identity”采用數據庫提供的主鍵生成機制。如DB2、SQL Server、MySQL 中的主鍵生成機制。

 
        

   “sequence”采用數據庫提供的 sequence 機制生成主鍵。如 Oralce 中的Sequence。

 
        

   “native”由 Hibernate 根據使用的數據庫自行判斷采用 identity、hilo、sequence 其中一種作為主鍵生成方式。

 
        

   “uuid.hex”由 Hibernate 基於128 位 UUID 算法 生成16 進制數值(編碼后以長度32 的字符串表示)作為主鍵。

 
        

   “uuid.string”與uuid.hex 類似,只是生成的主鍵未進行編碼(長度16),不能應用在 PostgreSQL 數據庫中。

 
        

   “foreign”使用另外一個相關聯的對象的標識符作為主鍵。

 
        

   以下舉例:
   1、指定參數的情況:
      <id name="id" unsaved-value="0"> 
        <generator class="sequence">
          <param name="sequence">SEQ_CHILD</param>
        </generator>
      </id>
     使用的是sequence,適合oracle數據庫;

 
        

   2、對於sql server2000中的數據庫子增字段,在配置文件使用下列方法實現:
      <id name="id" type="long" unsaved-value="0">
        <column name="id" sql-type="numeric" not-null="true" />
        <generator class="identity" /> 
      </id>
    這里主要是:identity:代表由sql server2000數據庫自己提供子增字段.如果要hibernate自己提供,則用increment關鍵字來實現

 
        

   3、如果表中的主鍵用字符串類型:可以用hibernate自己提供的方法實現主鍵唯一:
     <id name="id" type="string" unsaved-value="null">
         <column name="cid" sql-type="char(32)" not-null="true" />
         <generator class="uuid.hex" />
     </id>
     使用的是uuid.hex: 采用128位的算法來生成一個32位字符串。最通用的一種方式。適用於所有數據庫。

 
        

   重要的知識點:
   1. 如果有部門表,有員工表,員工表中有dep_id,則表部門類和員工類是one-to-many的關系:
      可以使用: ( 在部門類department中使用下列)
      Department類: 
        /** 部門的所有員工   */
       private Set staffs = new TreeSet();
     
       xml的文件:
         <set name="staffs" >
             <key column="dep_id"/>
             <one-to-many class="hbp.sys.data.Staff"/>
         </set>
         如果是list,需要用索引<index> </index>,具體其中的含義,不是很明白.待以后研究
      
    2. 如果部門要有一個負責人,即部門表(tb_department)中有一個字段:staff_id.
        那么表示部門和負責人之間的關系是many-to-one的關系
        Department類: 
         /** 部門負責人id */
       private Staff staff;
    
       xml 文件
        <many-to-one name="staff" class="hbp.sys.data.Staff" column="staff_id"/> 

    3. 多對多關系,一般我們是做一個中間關聯表.我用角色和權限做了個例子,
         Right(id,name)     Role(id,name)   中間表:tb_role_right(role_id,right_id)
         Right類中有一個Role的集合:private Set roles=new TreeSet();
         Role類中也有一個Right的集合:private Set rights=new TreeSet();
         則兩者是明顯的多對多關系.使用many-to-many來實現;
         xml文件中
         right.hbm.xml:如下:
           <set name="roles" table="tb_role_right" cascade="all">
              <key column="right_id"/>
              <many-to-many column="role_id" class="hbp.sys.data.Role"/>
           </set> 
         role.hbm.xml文件中類似:
           <set name="rights" table="tb_role_right" cascade="all">
             <key column="role_id"/>
             <many-to-many column="right_id" class="hbp.sys.data.Right"/>
           </set>

 
        

   4. 幾個值得注意的問題:
           a)在xml?映射文件中,寫類的名字時一定用類的全名:即:包+類名如:(hbp.sys.data.Staff),這個錯誤使我費了半天勁.:(
           b)我在寫實現基本DAO操作時,寫了
                session.delete("from Right as right where right.id="+id); 
                程序死活報錯,我折騰了半天,跟蹤到底,才恍然大悟,hibernate在解析sql語句的時候把
                其中的right,當成了數據庫中的右連接("保留字"),唉,這種關鍵字,不能隨便用啊,:)

 
        

   5. hibernate中HQL語言的查詢根據你的sql的不同而返回不同的對象類型.
            如果你使用session.find(String hql)
            一般會返回一個List,如:from Staff staff;返回的是包含所有的員工對象的集合
            如你的hql為:select count(*) from Staff staff;則返回的是一個Integer對象
            如果你使用的hql為:select count(distinct staff.name),count(*) from Staff staff;則返回的是一個Object
            即Object[],需要先把他轉換成Object[],然后在取[0],[1].
            這種設計我不知道hibernate是如何處理的,感覺既好也不好.好的是可以使用一個find獲得任意查詢
            不好在於根據hql來處理返回結果,容易出錯.

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM