Hibernate Session get()vs load()实例差异

时间:2020-02-23 14:41:26  来源:igfitidea点击:

Hibernate Session提供了从数据库中获取数据的不同方法。
其中两个是– get()和load()。
这些方法还有很多重载方法,我们可以在不同情况下使用。

乍看之下,get()load()看起来很相似,因为它们都是从数据库中获取数据,但是它们之间几乎没有什么区别,让我们以一个简单的例子来看一下。

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 HibernateGetVsLoad {

	public static void main(String[] args) {
		
		//Prep Work
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();
		Transaction tx = session.beginTransaction();
		
		//Get Example
		Employee emp = (Employee) session.get(Employee.class, new Long(2));
		System.out.println("Employee get called");
		System.out.println("Employee ID= "+emp.getId());
		System.out.println("Employee Get Details:: "+emp+"\n");
		
		//load Example
		Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
		System.out.println("Employee load called");
		System.out.println("Employee ID= "+emp1.getId());
		System.out.println("Employee load Details:: "+emp1+"\n");
		
		//Close resources
		tx.commit();
		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 get called
Employee ID= 2
Employee Get Details:: Id= 2, Name= David, Salary= 200.0, {Address= AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051}

Employee load called
Employee ID= 1
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 load Details:: Id= 1, Name= hyman, Salary= 100.0, {Address= AddressLine1= Albany Dr, City=San Jose, Zipcode=95129}

从输出中很明显,get()通过从数据库或者Hibernate 缓存中获取对象来返回对象,而load()仅返回可能不存在的对象的引用,它从数据库或者缓存中加载数据仅当您访问对象的其他属性时。

现在,让我们尝试获取数据库中不存在的数据。

//Get Example
try{
Employee emp = (Employee) session.get(Employee.class, new Long(200));
System.out.println("Employee get called");
if(emp != null){
System.out.println("Employee GET ID= "+emp.getId());
System.out.println("Employee Get Details:: "+emp+"\n");
}
}catch(Exception e){
	e.printStackTrace();
}

//load Example
try{
Employee emp1 = (Employee) session.load(Employee.class, new Long(100));
System.out.println("Employee load called");
System.out.println("Employee LOAD ID= "+emp1.getId());
System.out.println("Employee load Details:: "+emp1+"\n");
}catch(Exception e){
	e.printStackTrace();
}

上面的代码产生以下输出。

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 get called
Employee load called
Employee LOAD ID= 100
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=?
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.theitroad.hibernate.model.Employee#100]
	at org.hibernate.internal.SessionFactoryImpl.handleEntityNotFound(SessionFactoryImpl.java:253)
	at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:262)
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
	at com.theitroad.hibernate.model.Employee_$$_jvst407_1.toString(Employee_$$_jvst407_1.java)
	at java.lang.String.valueOf(String.java:2847)
	at java.lang.StringBuilder.append(StringBuilder.java:128)
	at com.theitroad.hibernate.main.HibernateExample.main(HibernateExample.java:36)

仔细观察输出,当我们使用get()检索不存在的数据时,它返回null。
这是有道理的,因为它会尝试在数据被调用后立即加载。

使用load(),我们可以打印id,但是当我们尝试访问其他字段时,它会触发数据库查询,如果没有找到具有给定标识符的记录,则会引发org.hibernate.ObjectNotFoundException。
它是Hibernate 专用的运行时异常,因此我们无需显式捕获它。

我们也来看看一些重载的方法。
上面的get()和load()方法也可以如下编写。

Employee emp = (Employee) session.get("com.theitroad.hibernate.model.Employee", new Long(2));

Employee emp1 = (Employee) session.load("com.theitroad.hibernate.model.Employee", new Long(1));

Employee emp2 = new Employee();
session.load(emp1, new Long(1));

还有其他带有LockOptions参数的方法,但是我没有使用过。
注意,我们需要传递完整的类名作为参数。

根据以上说明,get()与load()之间存在以下区别:

  • get()会在调用后立即加载数据,而load()返回代理对象并仅在实际需要时才加载数据,因此load()更好,因为它支持延迟加载。

  • 由于load()在找不到数据时会引发异常,因此仅当我们知道数据存在时才应使用它。

  • 当我们要确保数据库中存在数据时,应该使用get()