文章出處

一、Save()

save()方法能夠保存實體到數據庫。假如兩個實體之間有關系(例如employee表和address表有一對一關系),如果在沒有事務的情況下調用這個方法保存employee這個實體,除非調用flush()這個方法,否則僅僅employee實體會被保存。 

二、SaveOrUpdate()

 

saveOrUpdate()方法會執行插入或者更新操作。如果該對象在數據庫中已經存在則更新,不存在則插入。

 

也可以在沒有事務的情況下執行,但是如果沒有手動調用flush()方法會面臨關聯對象不被保存的問題

 

save()方法與saveOrUpdate()方法最大的不同點在于:saveOrUpdate()方法會將實體對象添加到持久化上下文中,該實體的后續改變會被跟蹤。

例子:

package nd.esp.com.hibernate.example;
 
import nd.esp.com.hibernate.model.Address;
import nd.esp.com.hibernate.model.Employee;
import nd.esp.com.hibernate.utils.HibernateUtil;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
public class HibernateSaveOrUpdateExample {
    public static void main(String[] args) {
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        System.out.println("***********************************************");
        // saveOrUpdate example - without transaction
        Session session5 = sessionFactory.openSession();
        Employee emp5 = getTestEmployee();
        session5.saveOrUpdate(emp5);
        System.out.println("***********************************************");
 
        // saveOrUpdate example - with transaction
        Session session3 = sessionFactory.openSession();
        Transaction tx3 = session3.beginTransaction();
        Employee emp3 = getTestEmployee();
        session3.saveOrUpdate(emp3);
        emp3.setName("Kumar"); // will be saved into DB
        System.out.println("9. Before committing saveOrUpdate transaction. Id=" + emp3.getId());
        tx3.commit();
        System.out.println("10. After committing saveOrUpdate transaction");
        System.out.println("***********************************************");
 
        Transaction tx4 = session3.beginTransaction();
        emp3.setName("Updated Test Name"); // Name changed
        emp3.getAddress().setCity("Updated City");
        session3.saveOrUpdate(emp3);
        emp3.setName("Kumar"); // again changed to previous value, so no Employee update
        System.out.println("11. Before committing saveOrUpdate transaction. Id=" + emp3.getId());
        tx4.commit();
        System.out.println("12. After committing saveOrUpdate transaction");
        System.out.println("***********************************************");
 
        // Close resources
        sessionFactory.close();
    }
    public static Employee getTestEmployee() {
        Employee emp = new Employee();
        Address add = new Address();
        emp.setName("Test Emp");
        add.setCity("Test City");
        emp.setAddress(add);
        add.setEmployee(emp);
        return emp;
    }
}

執行代碼,輸出結果:

***********************************************
Hibernate: insert into EMPLOYEE (emp_name) values (?)
***********************************************
Hibernate: insert into EMPLOYEE (emp_name) values (?)
9. Before committing saveOrUpdate transaction. Id=21
Hibernate: insert into ADDRESS (city, emp_id) values (?, ?)
Hibernate: update EMPLOYEE set emp_name=? where emp_id=?
10. After committing saveOrUpdate transaction
***********************************************
11. Before committing saveOrUpdate transaction. Id=21
Hibernate: update ADDRESS set city=? where emp_id=?
12. After committing saveOrUpdate transaction
***********************************************

注意:如果沒有事務,僅僅是employee實體被保存到數據庫,而address的信息丟失了。

在事務tx4中的幾行代碼employee實體的name屬性先被修改為“Updated Test Name”,之后又被賦值為原來的值“Kumar”,因此employee這個實體在事務提交之前并沒有改變,所以并沒有update操作。

三、Merge()

如果某對象處于游離態,游離態是指該對象的id值為空。hibernate判斷一個對象在數據庫中是否存在不是看對象的其他信息,而是判斷該id在數據庫中是不是存在。如果id為空,那自然是不存在,所以當我們調用merge方法的時候,就會直接執行插入操作。這一點有點像saveorupdate()方法。

 

Object merge(Object object)
             throws HibernateException

 

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge"
The semantics of this method are defined by JSR-220.
Parameters:
object - a detached instance with state to be copied
Returns:
an updated persistent instance
Throws:
HibernateException

 

首先從參數說明來看,merge的參數應該是一個處于托管狀態的實例對象,而返回值則是一個持久化對象。但是這里的參數并不是一定要是托管狀態的對象,它還可以是瞬態和持久化的實例對象。正因如此,才使merge方法變得復雜化。

 

經代碼檢驗從merge方法產生的效果來看,它和saveOrUpdate方法相似,因此雖然上面提到是因為參數狀態的不同造成復雜化,但是這里我并不打算分參數的不同狀態來理解merge,而是根據參數有無id或id是否已經存在來理解merge。個人認為這樣更容易理解,而且從執行他們兩個方法而產生的sql語句來看是一樣的。

 

1. 參數實例對象沒有提供id或提供的id在數據庫中不存在:這時merge將執行插入操作,產生的sql語句如下,       

 

          Hibernate: select max(uid) from user     

 

          Hibernate: insert into hibernate1.user (name, age, uid) values (?, ?, ?)

 

2. 參數實例對象的id在數據庫中已經存在,此時又有兩種情況:

 

(1)如果對象有改動,則執行更新操作,產生sql語句有,

 

         Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid=? 
         Hibernate: update hibernate1.user set name=?, age=? where uid=?

 

(2)如果對象為改動,則執行查詢操作,產生的語句有,

 

         Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid=?

 

不管哪種情況,merge的返回值都是一個持久化的實例對象,但對于參數而言不會改變它的狀態。

 

雖然從功能上merge方法與saveOrUpdate類似,但他們仍有區別。現在有這樣一種情況:我們先通過session的get方法得到一個對象u,然后關掉session,再打開一個session并執行saveOrUpdate(u)。此時我們可以看到拋出異常:Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session,即在session緩存中不允許有兩個id相同的對象。不過若使用merge方法則不會異常,其實從merge的中文意思(合并)我們就可以理解了。

 

 

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()