save(),saveOrUpdate(),merge()的區別


 Save

 save()方法能夠保存實體到數據庫,正如方法名稱save這個單詞所表明的意思。我們能夠在事務之外調用這個方法,這也是我不喜歡使用這個方法保存數據的原因。假如兩個實體之間有關系(例如employee表和address表有一對一關系),如果在沒有事務的情況下調用這個方法保存employee這個實體,除非調用flush()這個方法,否則僅僅employee實體會被保存。 

 saveOrUpdate

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

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

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

HibernateSaveOrUpdateExample.java

以下是簡單的hibernate程序,演示saveOrUpdate()方法的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
  * @(#)HibernateSaveOrUpdateExample.java    Created on 2016年4月10日
  * Copyright (c) 2016. All rights reserved.
  */
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;
     }
}

  

執行上述示例程序,輸出結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
***********************************************
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操作。

 

      下面來講講Hibernate的merge方法。我打算按照hibernate對象生命周期的三個狀態來講。

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

 
 

 

再看hibernate的sql語句:

 
 

 

二:脫管態:如果我們把上面代碼里//user.setId(4);的注釋去掉,那么它就變成了脫管的對象了(其實從游離到脫管就這么簡單,沒有官方說的那么邪乎...)。這是我們再來看控制台的sql打印:

 
 

 看到沒有,因為id不為空了,所以hibernate就不會再insert了。由於該對象的信息和數據庫里的一模一樣,所以hibernate只執行了一個select語句,並沒有update,如果我們把字段的值做稍微的變動,那么控制台打印的sql語句還應該有一條update語句。就這一點來說,merge還有和saveorupdate()方法一樣。

 

 

三:持久態:持久態更好理解。如果我們從數據庫里get一條記錄,那么這條記錄就處於持久態,如果再調用merge,那么hibernate就會先判斷該記錄是否被修改,沒有則什么也不干,修改了就update。這一點還是和saveorupdate()有點像。

  1. Session session = this.getSession();   
  2. Transaction tr = session.beginTransaction();   
  3. User exituser = (User)session.get(User.class, new Integer(1));   
  4. exituser.setAge(11);   
  5. session.merge(exituser);   
  6. tr.commit();   
  7. session.close();  
  1. Session session = this.getSession();  
  2. Transaction tr = session.beginTransaction();  
  3. User exituser = (User)session.get(User.class, new Integer(1));  
  4. exituser.setAge(11);  
  5. session.merge(exituser);  
  6. tr.commit();  
  7. session.close();  

 再看控制台打印結果:

 
 

  如果沒有對記錄進行修改則不會有后面的那條update語句。

 

那么merge和saveorupdate()到底有什么區別呢?看一段代碼:

 
 

 運行上面的代碼,hibernate給我們報了一個錯誤:a different object with the same identifier value was already associated with the session。意思是,在session緩存中以兩個標識相同的對象,這是不可以的。那么,吧update改成merge會怎么樣呢?改為merge后,一切OK,運行正常。其實merge在執行更新之前會將兩個標識符相同的對象進行合並,具體合並的方向是向exituser2合並。

 


免責聲明!

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



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