Hibernate Session合并,更新,保存,saveOrUpdate,持久化示例
Hibernate Session是Java应用程序和hibernate框架之间的接口。
今天,我们将探讨用于在表中保存和更新数据的Session重要方法-save,saveOrUpdate,持久化,更新和合并。
Hibernate 会话
Hibernate 会话保存
顾名思义,hibernate save()可用于将实体保存到数据库。
我们可以在交易外调用此方法,这就是为什么我不喜欢这种方法来保存数据的原因。
如果我们使用这个不交易,我们的实体之间的级联,那么只有主实体被保存,除非我们刷新了会议。
为了我们的测试目的,我们有两个实体Bean –"员工"和"地址"。
package com.theitroad.hibernate.model; import javax.persistence.Access; import javax.persistence.AccessType; 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") @Access(value=AccessType.FIELD) public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "emp_id") private long id; @Column(name = "emp_name") private String name; @Column(name = "emp_salary") private double salary; @OneToOne(mappedBy = "employee") @Cascade(value = org.hibernate.annotations.CascadeType.ALL) private Address address; //Getter setter methods @Override public String toString() { return "Id= " + id + ", Name= " + name + ", Salary= " + salary + ", {Address= " + address + "}"; } }
package com.theitroad.hibernate.model; import javax.persistence.Access; import javax.persistence.AccessType; 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") @Access(value=AccessType.FIELD) 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 = "address_line1") private String addressLine1; @Column(name = "zipcode") private String zipcode; @Column(name = "city") private String city; @OneToOne @PrimaryKeyJoinColumn private Employee employee; //Getter setter methods @Override public String toString() { return "AddressLine1= " + addressLine1 + ", City=" + city + ", Zipcode=" + zipcode; } }
这是一个简单的Hibernate 程序,在不同情况下,我们其中调用save()
方法。
package com.theitroad.hibernate.main; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Address; import com.theitroad.hibernate.model.Employee; import com.theitroad.hibernate.util.HibernateUtil; public class HibernateSaveExample { public static void main(String[] args) { //Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //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(20)); //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"); emp.setSalary(1000); add.setAddressLine1("Test address1"); add.setCity("Test City"); add.setZipcode("12121"); emp.setAddress(add); add.setEmployee(emp); return emp; } }
当我们执行以上程序时,它会产生以下输出。
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?) 1. Employee save called without transaction, id=149 Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?) * Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?) 2. Employee save called with transaction, id=150 3. Before committing save transaction Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?) 4. After committing save transaction * Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee Details=Id= 20, Name= Kumar1, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Blr, Zipcode=12121} 5. Employee save called with transaction, id=20 6. Before committing save transaction Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=? Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=? 7. After committing save transaction *
我们可以从上述输出中确认的几个要点是:
我们应避免在事务边界之外保存,否则将不会保存映射的实体,从而导致数据不一致。
忘记刷新会话非常正常,因为它不会引发任何异常或者警告。Hibernate save方法会立即返回生成的id,这是可能的,因为一旦调用save方法,就会保存主对象。
如果还有从主对象映射的其他对象,则在提交事务时或者在刷新会话时会保存它们。
对于处于持久状态的对象,保存将通过更新查询来更新数据。
请注意,它在提交事务时发生。
如果对象没有变化,则不会触发任何查询。
如果您将多次在该程序上运行,您会注意到下次不会触发更新查询,因为列值没有变化。Hibernate的负荷实体对象保存到持续背景下,如果你将保存呼叫,但在事务提交之前,它会被保存到数据库后更新对象的属性。
冬眠坚持
Hibernate持久性类似于保存(带有事务),并且将实体对象添加到持久性上下文中,因此可以跟踪任何进一步的更改。
如果在提交事务或者刷新会话之前更改了对象属性,则该对象属性还将保存到数据库中。
第二个区别是我们只能在事务范围内使用" persist()"方法,因此它是安全的,并且可以处理所有级联的对象。
最后,persist不返回任何内容,因此我们需要使用persisted对象来获取生成的标识符值。
让我们来看一个简单的程序保持Hibernate 状态。
package com.theitroad.hibernate.main; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Employee; import com.theitroad.hibernate.util.HibernateUtil; public class HibernatePersistExample { public static void main(String[] args) { //Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //persist example - with transaction Session session2 = sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); Employee emp2 = HibernateSaveExample.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(); } }
上面的代码产生的输出是:
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?) 8. Employee persist called with transaction, id=158, address id=158 Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?) Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=? *
请注意,首先插入了雇员对象,然后在提交事务时执行更新查询以更新名称值。
映射的对象地址也保存到数据库中。
Hibernate saveOrUpdate
Hibernate saveOrUpdate结果根据提供的数据插入或者更新查询。
如果数据库中存在数据,则执行更新查询。
我们也可以不使用事务而使用saveOrUpdate()
,但是如果会话不刷新,您将再次面临映射对象无法保存的问题。
Hibernate saveOrUpdate将实体对象添加到持久性上下文中并跟踪任何进一步的更改。
提交事务时将保存所有进一步的更改,例如persist。
package com.theitroad.hibernate.main; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Employee; import com.theitroad.hibernate.util.HibernateUtil; public class HibernateSaveOrUpdateExample { public static void main(String[] args) { //Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //saveOrUpdate example - without transaction Session session5 = sessionFactory.openSession(); Employee emp5 = HibernateSaveExample.getTestEmployee(); session5.saveOrUpdate(emp5); System.out.println("*"); //saveOrUpdate example - with transaction Session session3 = sessionFactory.openSession(); Transaction tx3 = session3.beginTransaction(); Employee emp3 = HibernateSaveExample.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(); } }
上面的程序产生以下输出。
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?) * Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?) 9. Before committing saveOrUpdate transaction. Id=166 Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?) Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=? 10. After committing saveOrUpdate transaction * 11. Before committing saveOrUpdate transaction. Id=166 Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=? 12. After committing saveOrUpdate transaction *
请注意,如果没有交易,则只会保存员工,而地址信息会丢失。
使用事务雇员对象跟踪是否有任何更改,这就是为什么即使在两次调用之间值都发生更改的情况下,在上次调用中Employee表中也没有更新的原因,最终值保持不变。
Hibernate 更新
当我们知道我们仅更新实体信息时,应使用Hibernate 更新。
此操作将实体对象添加到持久上下文中,并且在提交事务时跟踪并保存进一步的更改。
让我们用一个简单的程序来检查这种行为。
package com.theitroad.hibernate.main; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Employee; import com.theitroad.hibernate.util.HibernateUtil; public class HibernateUpdateExample { public static void main(String[] args) { //Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Employee emp = (Employee) session.load(Employee.class, new Long(101)); System.out.println("Employee object loaded. " + emp); tx.commit(); //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"); //Close resources sessionFactory.close(); } }
当我们第一次执行上面的程序时,我们得到以下输出。
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Id= 101, Name= Test Emp, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Test City, Zipcode=12121} 13. Before committing update transaction Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=? Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=? 14. After committing update transaction
在进一步执行时,我们得到以下输出。
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121} 13. Before committing update transaction 14. After committing update transaction
请注意,因为值没有更新,所以第一次执行后不会触发更新。
还要注意,员工名称是我们在调用update()方法后设置的"最终更新名称"。
这确认了Hibernate 状态正在跟踪对象的任何更改,并且在提交事务时已保存了该值。
Hibernate 合并
Hibernate merge可用于更新现有值,但是此方法从传递的实体对象创建一个副本并将其返回。
返回的对象是持久性上下文的一部分,并跟踪任何更改,不跟踪传递的对象。
这是与其他所有方法的merge()的主要区别。
让我们用一个简单的程序来看一下。
package com.theitroad.hibernate.main; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Employee; import com.theitroad.hibernate.util.HibernateUtil; public class HibernateMergeExample { public static void main(String[] args) { //Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Employee emp = (Employee) session.load(Employee.class, new Long(101)); System.out.println("Employee object loaded. " + emp); tx.commit(); //merge example - data already present in tables emp.setSalary(25000); Transaction tx8 = session.beginTransaction(); Employee emp4 = (Employee) session.merge(emp); System.out.println(emp4 == emp); //returns false emp.setName("Test"); emp4.setName("Kumar"); System.out.println("15. Before committing merge transaction"); tx8.commit(); System.out.println("16. After committing merge transaction"); //Close resources sessionFactory.close(); } }
第一次执行的输出是:
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121} false 15. Before committing merge transaction Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=? 16. After committing merge transaction
在进一步执行中,产生的输出为:
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Id= 101, Name= Kumar, Salary= 25000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121} false 15. Before committing merge transaction 16. After committing merge transaction
请注意,merge()返回的实体对象与传递的实体不同。
还要注意,在进一步执行中,名称为" Kumar",这是因为跟踪返回的对象是否有任何更改。