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.项目结构
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)
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