7-09 2,831 views
简介
Hibernate通过延迟加载在真正需要使用数据时从数据库表中加载,这样可以加快程序运行速度,减少内存开销。Hibernate在以下三种情况会默认使用延迟加载:
1)load方法延迟加载;
2)实体属性延迟加载;
3)集合属性延迟加载。
数据库示例
示例数据库包含3张表:
1)文章表(post),存储文章标题、内容,主键为自增整数;
2)分类表(category),存储分类名称,主键为自增整数;
3)标签表(score),存储标签名称,主键为自增整数;
4)文章标签表(post_tag),存储文章包含的标签,使用文章id和标签id作为联合主键。
每篇文章属于一个分类,并包含多个标签。
延迟加载示例
创建Post类与post表映射。
Post.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package com.magicwt.bean; import java.util.Set; public class Post { //与主键id映射 private int id; //与字段title映射 private String title; //与字段content映射 private String content; //关联Category实体 private Category category; //关联Tag实体 private Set<Tag> tags; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Category getCategory() { return category; } public void setCategory(Category category) { this.category = category; } public Set<Tag> getTags() { return tags; } public void setTags(Set<Tag> tags) { this.tags = tags; } } |
Post.hbm.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.magicwt.bean.Post" table="post"> <id name="id"> <column name="id" sql-type="int" not-null="true"/> </id> <property name="title"> <column name="title" sql-type="varchar" length="16"/> </property> <property name="content"> <column name="content" sql-type="text" length="65535"/> </property> <!-- 实体属性,对应于一个分类实体 --> <one-to-one name="category" class="com.magicwt.bean.Category" constrained="true"/> <!-- 集合属性,对应于多个标签实体 --> <set name="tags" table="post_tag" inverse="true"> <key column="post_id"/> <many-to-many column="tag_id" class="com.magicwt.bean.Tag"/> </set> </class> </hibernate-mapping> |
创建Category类与category表映射。
Category.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.magicwt.bean; public class Category { //与主键id映射 private int id; //与字段name映射 private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
Category.hbm.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.magicwt.bean.Category" table="category"> <id name="id"> <column name="id" sql-type="int" not-null="true"/> </id> <property name="name"> <column name="name" sql-type="varchar" length="16"/> </property> </class> </hibernate-mapping> |
创建Tag类与tag表映射。
Tag.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.magicwt.bean; public class Tag { //与主键id映射 private int id; //与字段name映射 private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
Tag.hbm.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.magicwt.bean.Tag" table="tag"> <id name="id"> <column name="id" sql-type="int" not-null="true"/> </id> <property name="name"> <column name="name" sql-type="varchar" length="16"/> </property> </class> </hibernate-mapping> |
Hibernate配置文件hibernate.cfg.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://xxx.xxx.xxx.xxx:3306/test</property> <property name="connection.username">xxx</property> <property name="connection.password">xxx</property> <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property> <property name="show_sql">true</property> <property name="hibernate.format_sql">true</property> <mapping resource="mapper/Category.hbm.xml"/> <mapping resource="mapper/Post.hbm.xml"/> <mapping resource="mapper/Tag.hbm.xml"/> </session-factory> </hibernate-configuration> |
load方法延迟加载
创建测试类Test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package com.magicwt; import com.magicwt.bean.Post; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class Test { public static void main(String[] args) { SessionFactory sessionFactory = (new Configuration()).configure().buildSessionFactory(); Session session = sessionFactory.openSession(); //使用load方法加载id为1的文章 Post post = (Post)session.load(Post.class, Integer.valueOf(1)); //输出post实例的类名 System.out.println("class of post: " + post.getClass().getCanonicalName()); //取出文章标题并输出 System.out.println(post.getTitle()); } } |
执行main方法,输出如下:
class of post: com.magicwt.bean.Post$$EnhancerByCGLIB$$70a21d16
Hibernate:
select
post0_.id as id1_0_,
post0_.title as title1_0_,
post0_.content as content1_0_
from
post post0_
where
post0_.id=?
title of post: 测试标题1
从中可以看出,load方法返回的是通过动态代理实现的代理类实例。通过断点可以观察到,执行“post.getTitle()”前,post实例各属性都是默认值(null或0),执行“post.getTitle()”后,才真正从数据库表中取出数据并输出。
将load方法修改为get方法并重新执行,输出如下:
Hibernate:
select
post0_.id as id1_0_,
post0_.title as title1_0_,
post0_.content as content1_0_
from
post post0_
where
post0_.id=?
class of post: com.magicwt.bean.Post
title of post: 测试标题1
从中可以看出,get方法返回的是Post类实例。通过断点可以观察到,get方法返回的post实例各属性已从数据库表中取出对应的值,get方法并没有延迟加载。
实体属性延迟加载
修改测试类Test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.magicwt; import com.magicwt.bean.Post; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class Test { public static void main(String[] args) { SessionFactory sessionFactory = (new Configuration()).configure().buildSessionFactory(); Session session = sessionFactory.openSession(); //使用load方法加载id为1的文章 Post post = (Post)session.get(Post.class, Integer.valueOf(1)); //输出post实例的类名 System.out.println("class of post: " + post.getClass().getCanonicalName()); //输出post实例category属性的类名 System.out.println("class of category: " + post.getCategory().getClass().getCanonicalName()); //输出分类名称 System.out.println("name of category:" + post.getCategory().getName()); } } |
执行main方法,输出如下:
Hibernate:
select
post0_.id as id1_0_,
post0_.title as title1_0_,
post0_.content as content1_0_
from
post post0_
where
post0_.id=?
class of post: com.magicwt.bean.Post
class of category: com.magicwt.bean.Category$$EnhancerByCGLIB$$483428f6
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
category category0_
where
category0_.id=?
name of category: 测试分类1
从中可以看出,get方法返回的post实例,其属性category是代理类实例,并没有真正读取category表中的数据,只有在输出分类名称时,才读取category表中的数据。
集合属性延迟加载
修改测试类Test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.magicwt; import com.magicwt.bean.Post; import com.magicwt.bean.Tag; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class Test { public static void main(String[] args) { SessionFactory sessionFactory = (new Configuration()).configure().buildSessionFactory(); Session session = sessionFactory.openSession(); //使用load方法加载id为1的文章 Post post = (Post)session.get(Post.class, Integer.valueOf(1)); //输出post实例的类名 System.out.println("class of post: " + post.getClass().getCanonicalName()); //输出post实例tags属性的类名 System.out.println("class of tags: " + post.getTags().getClass().getCanonicalName()); //输出标签名称 for (Tag tag : post.getTags()) { System.out.println("name of tag: " + tag.getName()); } } } |
执行main方法,输出如下:
Hibernate:
select
post0_.id as id1_0_,
post0_.title as title1_0_,
post0_.content as content1_0_
from
post post0_
where
post0_.id=?
class of post: com.magicwt.bean.Post
class of tags: org.hibernate.collection.PersistentSet
Hibernate:
select
tags0_.post_id as post1_1_,
tags0_.tag_id as tag2_1_,
tag1_.id as id3_0_,
tag1_.name as name3_0_
from
post_tag tags0_
left outer join
tag tag1_
on tags0_.tag_id=tag1_.id
where
tags0_.post_id=?
name of tag: 测试标签1
name of tag: 测试标签2
从中可以看出,get方法返回的post实例,其属性tags是PersistentSet实例,并没有真正读取tag表中的数据,只有在输出标签名称时,才读取tag表中的数据。
版权属于: 我爱我家
原文地址: http://magicwt.com/2013/07/09/hibernate%e7%9a%84%e5%bb%b6%e8%bf%9f%e5%8a%a0%e8%bd%bd/
转载时必须以链接形式注明原始出处及本声明。