博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【hibernate】Hibernate中save, saveOrUpdate, persist, merge, update 区别
阅读量:6342 次
发布时间:2019-06-22

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

Hibernate Save

hibernate save()方法能够保存实体到数据库,正如方法名称save这个单词所表明的意思。我们能够在事务之外调用这个方法,这也是我不喜欢使用这个方法保存数据的原因。假如两个实体之间有关系(例如employee表和address表有一对一关系),如果在没有事务的情况下调用这个方法保存employee这个实体,除非调用flush()这个方法,否则仅仅employee实体会被保存。

Employee.java

为了方便理解,简化Employee.java的属性。

/*  * @(#)Employee.java    Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */package nd.esp.com.hibernate.model;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; import org.hibernate.annotations.Cascade; @Entity @Table(name = "EMPLOYEE") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "emp_id") private long id; @Column(name = "emp_name") private String name; @OneToOne(mappedBy = "employee") @Cascade(value = org.hibernate.annotations.CascadeType.ALL) private Address address; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + "]"; } }

Address.java

为了方便理解,简化Address.java的属性。

/*  * @(#)Address.java    Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */package nd.esp.com.hibernate.model;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; @Entity @Table(name = "ADDRESS") public class Address { @Id @Column(name = "emp_id", unique = true, nullable = false) @GeneratedValue(generator = "gen") @GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") }) private long id; @Column(name = "city") private String city; @OneToOne @PrimaryKeyJoinColumn private Employee employee; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } @Override public String toString() { return "Address [id=" + id + ", city=" + city + "]"; } }

HibernateSaveExample.java

以下是简单的hibernate程序,演示save()方法的使用。

/*  * @(#)HibernateSaveExample.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 HibernateSaveExample { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); // save example - without transaction Session session = sessionFactory.openSession(); Employee emp = getTestEmployee(); long id = (Long) session.save(emp); System.out.println("1. Employee save called without transaction, id=" + id); session.flush(); // address will not get saved without this System.out.println("***********************************************"); // save example - with transaction Transaction tx1 = session.beginTransaction(); Session session1 = sessionFactory.openSession(); Employee emp1 = getTestEmployee(); long id1 = (Long) session1.save(emp1); System.out.println("2. Employee save called with transaction, id=" + id1); System.out.println("3. Before committing save transaction"); tx1.commit(); System.out.println("4. After committing save transaction"); System.out.println("***********************************************"); // save example - existing row in table Session session6 = sessionFactory.openSession(); Transaction tx6 = session6.beginTransaction(); Employee emp6 = (Employee) session6.load(Employee.class, new Long(3)); // update some data System.out.println("Employee Details=" + emp6); emp6.setName("New Name"); emp6.getAddress().setCity("New City"); long id6 = (Long) session6.save(emp6); emp6.setName("New Name1"); // will get updated in database System.out.println("5. Employee save called with transaction, id=" + id6); System.out.println("6. Before committing save transaction"); tx6.commit(); System.out.println("7. After committing save 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 (?) 1. Employee save called without transaction, id=15 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) *********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 2. Employee save called with transaction, id=16 3. Before committing save transaction 4. After committing save transaction *********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee Details=Employee [id=3, name=Test Emp] 5. Employee save called with transaction, id=3 6. Before committing save transaction Hibernate: update ADDRESS set city=? where emp_id=? Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 7. After committing save transaction ***********************************************

执行上述示例程序,输出结果(第二次)。

*********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 1. Employee save called without transaction, id=17 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) *********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 2. Employee save called with transaction, id=18 3. Before committing save transaction 4. After committing save transaction *********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee Details=Employee [id=3, name=New Name1] 5. Employee save called with transaction, id=3 6. Before committing save transaction 7. After committing save transaction ***********************************************

从上述的输出可以得到以下重要的几点:

  • 应该避免在事务之外调用save()方法,否则关联实体(例如employee和address是一对一关系,相互关联)将不会被保存从而导致不一致。很容易忘记在最后调用flush()方法,因为不会有任务的异常或者警告抛出。
  • hibernate save()方法会立即返回id,原因很可能是调用save()的同时这个实体对象已经被写入数据库(立即执行sql语句insert into)
  • 提交事务或者调用flush()方法,save()方法才会将关联对象也写入数据库。
  • save()方法保存持久化状态的对象,hibernate会通过update操作完成。注意这个会发生在提交事务的时候。如果该持久化对象没有改变,hibernate不会发出update语句。如果多次运行示例程序HibernateSaveExample.java,会发现从第二次开始程序就不会发送update语句。因为hibernate在更新之前会先select,查询该持久化对象,发现该对象和数据库中的一致,就不会做update操作。

Hibernate Persist

hibernate persist()方法与save()方法(在事务中执行)类似,persist()方法会将实体对象添加到持久化上下文中,如此被保存的实体后续改变会被记录。如果在提交事务或者会话flush(),对象的属性被重新赋值,那么这个变化也会被保存到数据库中。

第二个不同在于persist()方法只能够在事务内执行,所以它能够很好地保证关联对象的安全与存储(原文:Second difference is that we can use persist() method only within the boundary of a transaction, so it’s safe and takes care of any cascaded objects.)。(发现原作者的第一点让人很疑惑,感觉是persist()不在事务中执行就会报错。经过测试,persist()在事务外运行不会报错,但是不会插入数据到数据库。原作者的意思可能是:persist()方法只能够在事务中被执行,才能够将数据插入到数据库中)

最后,persist()方法返回值是void,也就是说不会返回任何的值。

HibernatePersistExample.java

以下是简单的hibernate程序,演示persist()方法的使用。

/*  * @(#)HibernatePersistExample.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 HibernatePersistExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); // persist example - with transaction Session session2 = sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); Employee emp2 = getTestEmployee(); session2.persist(emp2); System.out.println("Persist called"); emp2.setName("Kumar"); // will be updated in database too System.out.println("Employee Name updated"); System.out.println("8. Employee persist called with transaction, id=" + emp2.getId() + ", address id=" + emp2.getAddress().getId()); tx2.commit(); 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 (?) Persist called Employee Name updated 8. Employee persist called with transaction, id=19, address id=19 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) Hibernate: update EMPLOYEE set emp_name=? where emp_id=? ***********************************************

需要注意,第一次employee对象被插入数据库,提交事务的时候执行address实体的插入操作,由于employee实体name属性重新赋值,所以执行update操作。

Hibernate saveOrUpdate

hibernate saveOrUpdate()方法会执行插入或者更新操作。如果该对象在数据库中已经存在则更新,不存在则插入。

saveOrUpdate()方法可以在没有事务的情况下执行,但是如果没有手动调用flush()方法会面临关联对象不被保存的问题

save()方法与saveOrUpdate()方法最大的不同点在于,saveOrUpdate()方法会将实体对象添加到持久化上下文中,该实体的后续改变会被跟踪。

HibernateSaveOrUpdateExample.java

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

/*  * @(#)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; } }

执行上述示例程序,输出结果。

*********************************************** 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 update

当确定只更新实体信息时使用Hibernate update()方法。update()方法会将实体添加到持久化上下文,实体后续的改变会被跟踪并且当事务提交时这些改变会被保存到数据库中。

HibernateUpdateExample.java

以下是简单的hibernate程序,update()方法的使用。

/*  * @(#)HibernateUpdateExample.java    Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */package nd.esp.com.hibernate.example;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 HibernateUpdateExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Employee emp = (Employee) session.load(Employee.class, new Long(19)); System.out.println("Employee object loaded. " + emp); tx.commit(); System.out.println("***********************************************"); // update example emp.setName("Updated name"); emp.getAddress().setCity("Bangalore"); Transaction tx7 = session.beginTransaction(); session.update(emp); emp.setName("Final updated name"); System.out.println("13. Before committing update transaction"); tx7.commit(); System.out.println("14. After committing update transaction"); System.out.println("***********************************************"); // Close resources sessionFactory.close(); } }

执行上述示例程序,输出结果(第一次)。

*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=Kumar] *********************************************** 13. Before committing update transaction Hibernate: update ADDRESS set city=? where emp_id=? Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 14. After committing update transaction ***********************************************

执行上述示例程序,输出结果(第二次)。

*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=Final updated name] *********************************************** 13. Before committing update transaction 14. After committing update transaction ***********************************************

注意第二次运行并没有执行update操作,因为employee实体与数据库中的一致。还有语句:

session.update(emp);emp.setName("Final updated name");

修改employee实体name属性值为:“Final updated name”,是在update()方法之后,而最后保存到数据库中是“Final updated name”,表明hibernate update()方法会跟踪实体的改变,在提交事务时保存到数据库中。

Hibernate Merge

hibernate merge()方法被用于更新数据库中的记录,然而merge()方法通过创建一个传递进来的实体对象副本并且将这个副本作为返回值返回。返回值属于持久化上下文,能够跟踪实体的改变,而传递进来的实体并不能被跟踪。这一点是merge()方法与其他方法最大的不同。

HibernateMergeExample.java

以下是简单的hibernate程序,merge()方法的使用。

/*  * @(#)HibernateMergeExample.java    Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */package nd.esp.com.hibernate.example;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 HibernateMergeExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Employee emp = (Employee) session.load(Employee.class, new Long(19)); System.out.println("Employee object loaded. " + emp); tx.commit(); System.out.println("***********************************************"); // merge example - data already present in tables emp.setName("test1"); Transaction tx8 = session.beginTransaction(); Employee emp4 = (Employee) session.merge(emp); System.out.println(emp4 == emp); // returns false emp.setName("test2"); emp4.setName("merge"); System.out.println("15. Before committing merge transaction"); tx8.commit(); System.out.println("16. After committing merge transaction"); System.out.println("***********************************************"); // Close resources sessionFactory.close(); } }

执行上述示例程序,输出结果(第一次)。

*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=Kumar] *********************************************** false 15. Before committing merge transaction Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 16. After committing merge transaction ***********************************************

执行上述示例程序,输出结果(第二次)。

*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=merge] *********************************************** false 15. Before committing merge transaction 16. After committing merge transaction ***********************************************

注意merge()方法传递进入的实体与返回值实体是不一样的,

Employee emp4 = (Employee) session.merge(emp);emp.setName("test2");emp4.setName("merge");

上述代码会将employee表的name属性赋值为“merge”,因为返回实体emp4属于持久化上下文,会被跟踪改变。

以上内容翻译自。例子代码做了一点简化,并且工程化,可以在如下地址找到上述例子工程:

总结

save()方法:

  • 应该避免在事务之外调用save()方法,否则关联实体(例如employee和address是一对一关系,相互关联)将不会被保存从而导致不一致。很容易忘记在最后调用flush()方法,因为不会有任务的异常或者警告抛出。
  • hibernate save()方法会立即返回id,原因很可能是调用save()的同时这个实体对象已经被写入数据库(立即执行sql语句insert into)
  • 提交事务或者调用flush()方法,save()方法才会将关联对象也写入数据库。

persist()方法:

  • persist()方法会将实体对象添加到持久化上下文中,如此被保存的实体后续改变会被记录。如果在提交事务或者会话flush(),对象的属性被重新赋值,那么这个变化也会被保存到数据库中。
  • persist()方法必须在事务内执行,才能够将数据插入数据库。如果不在事务范围内执行,数据将丢失。
  • 最后,persist()方法返回值是void,也就是说不会返回任何的值。

saveOrUpdate()方法:

  • hibernate saveOrUpdate()方法会执行插入或者更新操作。如果该对象在数据库中已经存在则更新,不存在则插入。
  • saveOrUpdate()方法可以在没有事务的情况下执行,但是如果没有手动调用flush()方法会面临关联对象不被保存的问题
  • save()方法与saveOrUpdate()方法最大的不同点在于,saveOrUpdate()方法会将实体对象添加到持久化上下文中,该实体的后续改变会被跟踪。

update()方法:

  • 当确定只更新实体信息时使用Hibernate update()方法。update()方法会将实体添加到持久化上下文,实体后续的改变会被跟踪并且当事务提交时这些改变会被保存到数据库中
  • hibernate update()方法会跟踪实体的改变,在提交事务时保存到数据库中。

merge()方法:

  • hibernate merge()方法被用于更新数据库中的记录,然而merge()方法通过创建一个传递进来的实体对象副本并且将这个副本作为返回值返回。返回值属于持久化上下文,能够跟踪实体的改变,而传递进来的实体并不能被跟踪。这一点是merge()方法与其他方法最大的不同。

 

转载自:

转载于:https://www.cnblogs.com/sxdcgaq8080/p/8836302.html

你可能感兴趣的文章
创建符合标准的、有语意的HTML页面——ASP.NET 2.0 CSS Friendly Control Adapters 1.0发布...
查看>>
Adobe驳斥Flash过度耗电论 称HTML5更耗电
查看>>
No!No!No! It's not fashion!
查看>>
艰困之道中学到的经验教训
查看>>
互联网生态建设落地五大挑战——保险科技生态建设 ...
查看>>
进行短视频app开发工作时,可以加入它来保护青少年 ...
查看>>
25G DAC无源高速线缆和25G光模块之间的区别
查看>>
乐乐茶完成近2亿元Pre-A轮融资,祥峰投资领投
查看>>
clickhouse修改时区
查看>>
CSS_定位
查看>>
第二十四章:页面导航(六)
查看>>
10 个 Linux 中方便的 Bash 别名
查看>>
全新 DOCKER PALS 计划上线,带给您不一样的参会体验! ...
查看>>
Android开发之自定义View(二)
查看>>
python爬虫之微打赏(scrapy版)
查看>>
自制操作系统Antz day08——实现内核 (中) 扩展内核
查看>>
poj-1056-IMMEDIATE DECODABILITY(字典)
查看>>
区块链应用 | 不知道什么时候起,满世界都在谈区块链的事情
查看>>
小程序爆红 专家:对简单APP是巨大打击
查看>>
FarBox--另类有趣的网站服务【转】
查看>>