博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
save(),saveOrUpdate(),merge()的区别
阅读量:6623 次
发布时间:2019-06-25

本文共 5102 字,大约阅读时间需要 17 分钟。

 

 

 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合并。

转载于:https://www.cnblogs.com/Smile-123/p/5826763.html

你可能感兴趣的文章
win10系统设置webp文件默认用照片查看器打开的两种方法
查看>>
使用阿里云发送邮件
查看>>
Tomcat监听器设计思路
查看>>
react native 入门之javascript
查看>>
管理ORACLE实例
查看>>
Confluence 6 MySQL 数据库设置准备
查看>>
Ruby 中 0/0.0 = NaN
查看>>
JEESNS数据库表设计结构
查看>>
JavaScript学习笔记:判断变量是否为undefined,判断变量和函数是否声明
查看>>
局域网访问Apache服务器
查看>>
我的友情链接
查看>>
SpringMVC中用于绑定请求数据的注解以及配置视图解析器
查看>>
JavaScript 闭包
查看>>
如何修改远程桌面3389端口
查看>>
Anthos Config Management 产品设计分析
查看>>
我的友情链接
查看>>
Spark算子:RDD行动Action操作(3)–aggregate、fold、lookup
查看>>
UILabel总结
查看>>
java获取当前时间前一周、前一月、前一年的时间
查看>>
话说WEB开发之页面重绘和回流
查看>>