Hibernate之get()和load()

get()和load()都是从数据库中检索对象,二者最大的区别就是load()支持延迟加载,而get()不支持延迟加载,是立即检索的策略。

分析get()和load()主要分析类级别的检索策略,立即检索和延迟检索。

类级别的默认检索方式有些书上写的是立即检索,事实证明默认检索方式是延迟检索。

1.立即检索

在xxx.hbm.xml配置文件中,配置成以下方式是立即检索的方式:

<class name="Customer" table="CUSTOMERS" select-before-update="true" lazy="false" >

当通过session的load()方法检索Customer对象或通过get()检索Customer对象时:

Customer customer = (Customer) session.load(Customer.class, new Long(1));

Hibernate会立刻执行select语句查询CUSTOMERS表,控制台打印的sql语句:

select customer0_.ID as ID1_0_0_, customer0_.NAME as NAME2_0_0_, customer0_.EMAIL as EMAIL3_0_0_, customer0_.PASSWORD as PASSWORD4_0_0_, customer0_.PHONE as PHONE5_0_0_, customer0_.ADDRESS as ADDRESS6_0_0_, customer0_.SEX as SEX7_0_0_, customer0_.IS_MARRIED as IS8_0_0_, customer0_.DESCRIPTION as DESCRIPT9_0_0_, customer0_.IMAGE as IMAGE10_0_0_, customer0_.BIRTHDAY as BIRTHDA11_0_0_, customer0_.REGISTERED_TIME as REGISTE12_0_0_, customer0_.HOME_PROVINCE as HOME13_0_0_, customer0_.HOME_CITY as HOME14_0_0_, customer0_.HOME_STREET as HOME15_0_0_, customer0_.HOME_ZIPCODE as HOME16_0_0_, customer0_.COMP_PROVINCE as COMP17_0_0_, customer0_.COMP_CITY as COMP18_0_0_, customer0_.COMP_STREET as COMP19_0_0_, customer0_.COMP_ZIPCODE as COMP20_0_0_ from CUSTOMERS customer0_ where customer0_.ID=?

这种立即检索的方式,get()和load()会立刻执行select语句,从数据库查询,初始化Customer对象。

关于立即检索的实例如下:

运行项目之前可以先创建表,或者通过hibernate完成表的创建。

CREATE TABLE `CUSTOMERS` (
  `ID` bigint(20) NOT NULL,
  `NAME` varchar(25) NOT NULL,
  `EMAIL` varchar(255) NOT NULL,
  `PASSWORD` varchar(255) NOT NULL,
  `PHONE` int(11) DEFAULT NULL,
  `ADDRESS` varchar(255) DEFAULT NULL,
  `SEX` char(1) DEFAULT NULL,
  `IS_MARRIED` tinyint(1) DEFAULT NULL,
  `DESCRIPTION` longtext,
  `IMAGE` tinyblob,
  `BIRTHDAY` date DEFAULT NULL,
  `REGISTERED_TIME` datetime DEFAULT NULL,
  `HOME_PROVINCE` varchar(255) DEFAULT NULL,
  `HOME_CITY` varchar(255) DEFAULT NULL,
  `HOME_STREET` varchar(255) DEFAULT NULL,
  `HOME_ZIPCODE` smallint(6) DEFAULT NULL,
  `COMP_PROVINCE` varchar(255) DEFAULT NULL,
  `COMP_CITY` varchar(255) DEFAULT NULL,
  `COMP_STREET` varchar(255) DEFAULT NULL,
  `COMP_ZIPCODE` smallint(6) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

1.项目结构

Hibernate之get()和load()_第1张图片

2.创建实体

Customer.java:

package com.lanhuigu.hibernate.entity;

import java.io.Serializable;
import java.util.Date;

import com.sun.jmx.snmp.Timestamp;

/**
 * 创建java持久化类,就是需要被持久化到数据库中的实体类 
 */
public class Customer implements Serializable{

	private static final long serialVersionUID = 9026723017886524518L;
	private Long id;
	private String name;
	private String email;
	private String password;
	private int phone;
	private boolean married;
	private String address;
	private char sex;
	private String description;
	private byte[] image;
	private Date birthday;
	private Timestamp registeredTime;
	private Address homeAddress;
	private Address compAddress;
	
	public Customer(){}

	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 String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public int getPhone() {
		return phone;
	}

	public void setPhone(int phone) {
		this.phone = phone;
	}

	public boolean isMarried() {
		return married;
	}

	public void setMarried(boolean married) {
		this.married = married;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public char getSex() {
		return sex;
	}

	public void setSex(char sex) {
		this.sex = sex;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public byte[] getImage() {
		return image;
	}

	public void setImage(byte[] image) {
		this.image = image;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public Timestamp getRegisteredTime() {
		return registeredTime;
	}

	public void setRegisteredTime(Timestamp registeredTime) {
		this.registeredTime = registeredTime;
	}

	public Address getHomeAddress() {
		return homeAddress;
	}

	public void setHomeAddress(Address homeAddress) {
		this.homeAddress = homeAddress;
	}

	public Address getCompAddress() {
		return compAddress;
	}

	public void setCompAddress(Address compAddress) {
		this.compAddress = compAddress;
	}
}
Address.java:

package com.lanhuigu.hibernate.entity;

import java.io.Serializable;
/**
 * 地址实体类
 */
public class Address implements Serializable{

	private static final long serialVersionUID = -1450327776636898762L;
	private String province;
	private String city;
	private String street;
	private Short zipcode;
	private Customer customer;
	
	public String getProvince() {
		return province;
	}
	public void setProvince(String province) {
		this.province = province;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getStreet() {
		return street;
	}
	public void setStreet(String street) {
		this.street = street;
	}
	public Short getZipcode() {
		return zipcode;
	}
	public void setZipcode(Short zipcode) {
		this.zipcode = zipcode;
	}
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}

3.Customer.hbm.xml配置文件(对象-映射文件)

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping  package="com.lanhuigu.hibernate.entity" >
		<class name="Customer" table="CUSTOMERS" select-before-update="true" lazy="false" >
			<!-- 设置主键 -->
			<id name="id" column="ID" type="long">
				<!-- 主键生成方式-->
				<generator class="increment"/>
			</id>
			<!-- 基本属性,基本属性必须设置在主键之口-->
			<property name="name" column="NAME" type="string" length="25" not-null="true" access="property"/>
			<property name="email" column="EMAIL" type="string" not-null="true" />
			<property name="password" column="PASSWORD" type="string" not-null="true" />
			<property name="phone" column="PHONE" type="int" />
			<property name="address" column="ADDRESS" type="string" />
			<property name="sex" column="SEX" type="character" />
			<property name="married" column="IS_MARRIED" type="boolean" />
			<property name="description" column="DESCRIPTION" type="text" />
			<property name="image" column="IMAGE" type="binary" />
			<property name="birthday" column="BIRTHDAY" type="date" />
			<property name="registeredTime" column="REGISTERED_TIME" type="timestamp" insert="false" update="false"/>
			<!-- 部分类 -->
			<component name="homeAddress" class="Address">
				<parent name="customer"/>
				<property name="province" type="string" column="HOME_PROVINCE"></property>
				<property name="city" type="string" column="HOME_CITY"></property>
				<property name="street" type="string" column="HOME_STREET"></property>
				<property name="zipcode" type="short" column="HOME_ZIPCODE"></property>
			</component>
			
			<component name="compAddress" class="Address">
				<parent name="customer"/>
				<property name="province" type="string" column="COMP_PROVINCE"></property>
				<property name="city" type="string" column="COMP_CITY"></property>
				<property name="street" type="string" column="COMP_STREET"></property>
				<property name="zipcode" type="short" column="COMP_ZIPCODE"></property>
			</component>
		</class>
	
</hibernate-mapping>

4.hibernate.cfg.xml配置文件

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- hibernate-configuration为hibernate配置头文件 -->
<hibernate-configuration>
	<!-- 配置session-factory,
	     SessionFactory是Hibernate的工厂类,
	              该类负责Hibernate的配置和Hiberante的Session接口中save(),update(),delete(),load(),find()的操作  
	-->
	<session-factory>
		<!-- 1.数据库连接配置 -->
		<!-- 数据库连接url -->
		<property name="connection.url">jdbc:mysql://192.168.200.12:3306/hbtest</property>
		<!-- 数据库连接用户名 -->
		<property name="connection.username">root</property>
		<!-- 数据库连接口令 -->
		<property name="connection.password">root123</property>
		<!-- 数据库连接驱动 -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<!-- 数据库方言 -->
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
		<!-- 数据库连接池大小配置 -->
		<property name="connection.pool_size">1</property>
		
		<!-- 配置使用二级缓存的类 -->
		<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
		<!-- 一次读的数据库记录数 -->
		<property name="jdbc.fetch_size">50</property>
		<!-- 设定对数据库进行批量删除条数 -->
		<property name="jdbc.batch_size">30</property>
		
		<!-- 2.是否打印sql配置 -->
		<property name="show_sql">true</property>
		
		<!-- 3.对象-映射关系文件的位置 -->
		<mapping resource="com/lanhuigu/hibernate/entity/Customer.hbm.xml" />
	
	</session-factory>
</hibernate-configuration>

5.TestSessionLazy

package com.lanhuigu.hibernate.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.lanhuigu.hibernate.entity.Customer;

public class TestSessionLazy {
	public static void main(String[] args) {
		//1.读取hibernate.cfg.xml文件(完成数据库配置,映射文件的加载,以及SessionFactory创建)
		Configuration cfg = new Configuration().configure();//默认读取/hibernate.cfg.xml配置文件
		//2.获取配置文件创建的session工厂
		SessionFactory sessionFactory = cfg.buildSessionFactory();
		//3.从session工厂中拿到Session对象
		Session session = sessionFactory.openSession();
		//4.打开事务
		Transaction tr = session.beginTransaction();
		//5.调用session的方法
		//get
		//Customer customer = (Customer) session.get(Customer.class, new Long(1));
		//load
		Customer customer = (Customer) session.load(Customer.class, new Long(1));
		System.out.println(customer.getName());
		//System.out.println(customer.getId());
		//6.提交事务
		tr.commit();
		//7.关闭session,清空缓存
		session.close();
	}
}
执行分析:

<class name="Customer" table="CUSTOMERS" select-before-update="true" lazy="false" >为立即检索设置,

load(),get()立刻执行select语句,初始化customer对象。

2.延迟检索

两种延迟检索的设置方式:

默认或者lazy设置成true:

<class name="Customer" table="CUSTOMERS" select-before-update="true" >

<class name="Customer" table="CUSTOMERS" select-before-update="true" lazy="true" >

get()方法对于延迟检索是没有影响的,就算设置成延迟检索,get()同样立刻执行select查询表,初始化customer对象。

load()方法并不会立刻执行select语句查询数据库,返回的是一个代理类实例,代理类具有以下特点:

(1)hibernate动态生成,扩展了Customer类,继承了Customer类的所有属性和方法,对于应用程序透明。

(2)hibernate创建Customer代理实例的时候仅仅初始化了OID属性,其他属性都是空的,这个代理类占用内存最少。

(3)当应用程序第一次访问代理类实例时,System.out.println(customer.getName());,会立刻执行select查询语句。

       特别注意的是,当你访问id,即为:System.out.println(customer.getId());时,不会去执行select语句,初始化Customer对象。

get()对于延迟检索没有什么特别的,但是load()在运行时有很多特征,都是指延迟检索时:

(1)如果加载Customer对象时数据库中不存在,Session的load()不会抛异常,只有调用动态代理类对象时,才会抛异常。

我以上程序换一个数据库没有的数据,测试:

Customer customer = (Customer) session.load(Customer.class, new Long(8));

当你运行时是不会报错的,前提是你设置成延迟检索,lazy='true'或默认,如果lazy='false'会立刻报错。

但是,当你访问时,马上报错:

System.out.println(customer.getName());

控制台错误:

Hibernate: select customer0_.ID as ID1_0_0_, customer0_.NAME as NAME2_0_0_, customer0_.EMAIL as EMAIL3_0_0_, customer0_.PASSWORD as PASSWORD4_0_0_, customer0_.PHONE as PHONE5_0_0_, customer0_.ADDRESS as ADDRESS6_0_0_, customer0_.SEX as SEX7_0_0_, customer0_.IS_MARRIED as IS8_0_0_, customer0_.DESCRIPTION as DESCRIPT9_0_0_, customer0_.IMAGE as IMAGE10_0_0_, customer0_.BIRTHDAY as BIRTHDA11_0_0_, customer0_.REGISTERED_TIME as REGISTE12_0_0_, customer0_.HOME_PROVINCE as HOME13_0_0_, customer0_.HOME_CITY as HOME14_0_0_, customer0_.HOME_STREET as HOME15_0_0_, customer0_.HOME_ZIPCODE as HOME16_0_0_, customer0_.COMP_PROVINCE as COMP17_0_0_, customer0_.COMP_CITY as COMP18_0_0_, customer0_.COMP_STREET as COMP19_0_0_, customer0_.COMP_ZIPCODE as COMP20_0_0_ from CUSTOMERS customer0_ where customer0_.ID=?
Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.lanhuigu.hibernate.entity.Customer#8]
	at org.hibernate.internal.SessionFactoryImpl$1$1.handleEntityNotFound(SessionFactoryImpl.java:244)
	at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:261)
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:175)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
	at com.lanhuigu.hibernate.entity.Customer_$$_javassist_0.getName(Customer_$$_javassist_0.java)
	at com.lanhuigu.hibernate.test.TestSessionLazy.main(TestSessionLazy.java:25)

(2)如果在Session范围内,没有访问过Customer对象,Customer对象就没有被初始化,当你访问游离对象时,报错。

package com.lanhuigu.hibernate.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.lanhuigu.hibernate.entity.Customer;

public class TestSessionLazy {
	public static void main(String[] args) {
		//1.读取hibernate.cfg.xml文件(完成数据库配置,映射文件的加载,以及SessionFactory创建)
		Configuration cfg = new Configuration().configure();//默认读取/hibernate.cfg.xml配置文件
		//2.获取配置文件创建的session工厂
		SessionFactory sessionFactory = cfg.buildSessionFactory();
		//3.从session工厂中拿到Session对象
		Session session = sessionFactory.openSession();
		//4.打开事务
		Transaction tr = session.beginTransaction();
		//5.调用session的方法
		//get
		//Customer customer = (Customer) session.get(Customer.class, new Long(1));
		//load
		Customer customer = (Customer) session.load(Customer.class, new Long(1));
		//System.out.println(customer.getName());
		//System.out.println(customer.getId());
		//6.提交事务
		tr.commit();
		//7.关闭session,清空缓存
		session.close();
		//session范围内没有访问Customer对象,没有被初始化,session关闭时,访问一个没有初始化的游离对象,报错
		System.out.println(customer.getName());
	}
}
错误如下:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
	at com.lanhuigu.hibernate.entity.Customer_$$_javassist_0.getName(Customer_$$_javassist_0.java)
	at com.lanhuigu.hibernate.test.TestSessionLazy.main(TestSessionLazy.java:31)
(3)前面说过的访问getId()时,不会触发Hibernate执行select语句。

    System.out.println(customer.getId());

    控制台可以看出不会有sql打印出,但是把获得的id打印出来。

(4)Hibernate.isInitialized(customer),判断动态代理类是不是已经被初始化,初始化为true,否则为false。

        Hibernate.initialize(customer);//初始化动态代理对象

package com.lanhuigu.hibernate.test;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.lanhuigu.hibernate.entity.Customer;

public class TestSessionLazy {
	public static void main(String[] args) {
		//1.读取hibernate.cfg.xml文件(完成数据库配置,映射文件的加载,以及SessionFactory创建)
		Configuration cfg = new Configuration().configure();//默认读取/hibernate.cfg.xml配置文件
		//2.获取配置文件创建的session工厂
		SessionFactory sessionFactory = cfg.buildSessionFactory();
		//3.从session工厂中拿到Session对象
		Session session = sessionFactory.openSession();
		//4.打开事务
		Transaction tr = session.beginTransaction();
		//5.调用session的方法
		//get
		//Customer customer = (Customer) session.get(Customer.class, new Long(1));
		//load
		Customer customer = (Customer) session.load(Customer.class, new Long(1));
		if(Hibernate.isInitialized(customer)){//判断动态代理类是不是已经被初始化,初始化为true,否则为false
			System.out.println("被初始化");
		} else {
			System.out.println("没有被初始化");
			Hibernate.initialize(customer);//初始化动态代理对象
			System.out.println(Hibernate.isInitialized(customer));
		}
		//System.out.println(customer.getName());
		//System.out.println(customer.getId());
		//6.提交事务
		tr.commit();
		//7.关闭session,清空缓存
		session.close();
		//session范围内没有访问Customer对象,没有被初始化,session关闭时,访问一个没有初始化的游离对象,报错
		//System.out.println(customer.getName());
	}
}
控制台打印结果:

没有被初始化
Hibernate: select customer0_.ID as ID1_0_0_, customer0_.NAME as NAME2_0_0_, customer0_.EMAIL as EMAIL3_0_0_, customer0_.PASSWORD as PASSWORD4_0_0_, customer0_.PHONE as PHONE5_0_0_, customer0_.ADDRESS as ADDRESS6_0_0_, customer0_.SEX as SEX7_0_0_, customer0_.IS_MARRIED as IS8_0_0_, customer0_.DESCRIPTION as DESCRIPT9_0_0_, customer0_.IMAGE as IMAGE10_0_0_, customer0_.BIRTHDAY as BIRTHDA11_0_0_, customer0_.REGISTERED_TIME as REGISTE12_0_0_, customer0_.HOME_PROVINCE as HOME13_0_0_, customer0_.HOME_CITY as HOME14_0_0_, customer0_.HOME_STREET as HOME15_0_0_, customer0_.HOME_ZIPCODE as HOME16_0_0_, customer0_.COMP_PROVINCE as COMP17_0_0_, customer0_.COMP_CITY as COMP18_0_0_, customer0_.COMP_STREET as COMP19_0_0_, customer0_.COMP_ZIPCODE as COMP20_0_0_ from CUSTOMERS customer0_ where customer0_.ID=?
true




你可能感兴趣的:(get,load,检索策略,延迟检索,立即检索)