推迟加载:
推迟加载机制是号码大全为了防止一些无谓的功用开支而提出来关键词挖掘工具的,所谓推迟加载即是当在真实需求数据的时分,才真实履行数据加载操作。在Hibernate中供给了对实体方针的推迟加载以及对调集的推迟加载,另外在Hibernate3中还供给了对特点的推迟加载。下面咱们就别离介绍这些品种的推迟加载的细节。
A、实体方针的推迟加载:
假如想对实体方针运用推迟加载,有必要要在实体的映射装备文件中进行相应的装备,如下所示:
?
……
经过将class的lazy特点设置为true,来敞开实体的推迟加载特性。假如咱们运转下面的代码:
User user=(User)session.load(User.class,”1”);(1)
System.out.println(user.getName());(2)
当运转到(1)处时,Hibernate并没有建议对数据的查询,假如咱们此刻经过一些调试东西(比方JBuilder2005的Debug东西),调查此刻user方针的内存快照,咱们会惊奇的发现,此刻回来的可能是User$EnhancerByCGLIB$$bede8986类型的方针,并且其特点为null,这是怎么回事?还记得前面我曾讲过session.load()办法,会回来实体方针的署理类方针,这儿所回来的方针类型即是User方针的署理类方针。在Hibernate中经过运用CGLIB,来完结动态结构一个方针方针的署理类方针,并且在署理类方针中包含方针方针的一切特点和办法,并且一切特点均被赋值为null。经过调试器显现的内存快照,咱们能够看出此刻真实的User方针,是包含在署理方针的CGLIB$CALBACK_0.target特点中,当代码运转到(2)处时,此刻调用user.getName()办法,这时经过CGLIB赋予的回调机制,实践上调用CGLIB$CALBACK_0.getName()办法,当调用该办法时,Hibernate会首先查看CGLIB$CALBACK_0.target特点是不是为null,假如不为空,则调用方针方针的getName办法,假如为空,则会建议数据库查询,生成相似这样的SQL句子:select * from user where id=’1’;来查询数据,并结构方针方针,并且将它赋值到CGLIB$CALBACK_0.target特点中。
这样,经过一个中心署理方针,Hibernate完结了实体的推迟加载,只要当用户真实建议获得实体方针特点的动作时,才真实会建议数据库查询操作。所以实体的推迟加载是用经过中心署理类完结的,所以只要session.load()办法才会运用实体推迟加载,由于只要session.load()办法才会回来实体类的署理类方针。
B、调集类型的推迟加载:
在Hibernate的推迟加载机制中,对于调集类型的运用,含义是最为严重的,由于这有可能使功用得到大幅度的提高,为此Hibernate进行了很多的尽力,其间包括对JDK Collection的独立完结,咱们在一对多相关中,定义的用来容纳相关方针的Set调集,并不是java.util.Set类型或其子类型,而是net.sf.hibernate.collection.Set类型,经过运用自定义调集类的完结,Hibernate完结了调集类型的推迟加载。为了对调集类型运用推迟加载,咱们有必要如下装备咱们的实体类的对于相关的有些:
…..
经过将元素的lazy特点设置为true来敞开调集类型的推迟加载特性。咱们看下面的代码:
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses(); (1)
Iterator it=addset.iterator(); (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
当程序履行到(1)处时,这时并不会建议对相关数据的查询来加载相关数据,只要运转到(2)处时,真实的数据读取操作才会开端,这时Hibernate会依据缓存中契合条件的数据索引,来查找契合条件的实体方针。
这儿咱们引入了一个全新的概念——数据索引,下面咱们首先将讲一下啥是数据索引。在Hibernate中对调集类型进行缓存时,是分两有些进行缓存的,首先缓存调集中一切实体的id列表,然后缓存实体方针,这些实体方针的id列表,即是所谓的数据索引。当查找数据索引时,假如没有找到对应的数据索引,这时就会一条select SQL的履行,获得契合条件的数据,并结构实体方针调集和数据索引,然后回来实体方针的调集,并且将实体方针和数据索引归入Hibernate的缓存之中。另一方面,假如找到对应的数据索引,则从数据索引中取出id列表,然后依据id在缓存中查找对应的实体,假如找到就从缓存中回来,假如没有找到,在建议select SQL查询。在这儿咱们看出了另外一个疑问,这个疑问可能会对功用产生影响,这即是调集类型的缓存战略。假如咱们如下装备调集类型:
…..
这儿咱们运用了装备,假如选用这种战略来装备调集类型,Hibernate将只会对数据索引进行缓存,而不会对调集中的实体方针进行缓存。如上装备咱们运转下面的代码:
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses();
Iterator it=addset.iterator();
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
System.out.println(“Second query……”);
User user2=(User)session.load(User.class,”1”);
Collection it2=user2.getAddresses();
while(it2.hasNext()){
Address address2=(Address)it2.next();
System.out.println(address2.getAddress());
}
运转这段代码,会得到相似下面的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Select * from address where id=’1’;
Select * from address where id=’2’;
Tianjin
Dalian
咱们看到,当第2次履行查询时,履行了两条对address表的查询操作,为啥会这样?这是由于当第一次加载实体后,依据调集类型缓存战略的装备,只对调集数据索引进行了缓存,而并没有对调集中的实体方针进行缓存,所以在第2次再次加载实体时,Hibernate找到了对应实体的数据索引,可是依据数据索引,却无法在缓存中找到对应的实体,所以Hibernate依据找到的数据索引建议了两条select SQL的查询操作,这儿造成了对功用的糟蹋,怎样才能防止这种状况呢?咱们有必要对调集类型中的实体也指定缓存战略,所以咱们要如下对调集类型进行装备:
…..
此刻Hibernate会对调集类型中的实体也进行缓存,假如依据这个装备再次运转上面的代码,将会得到相似如下的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Tianjin
Dalian
这时将不会再有依据数据索引进行查询的SQL句子,由于此刻能够直接从缓存中获得调集类型中寄存的实体方针。
C、特点推迟加载:
在Hibernate3中,引入了一种新的特性——特点的推迟加载,这个机制又为获取高功用查询供给了有力的东西。在前面咱们讲大数据方针读取时,在User方针中有一个resume字段,该字段是一个java.sql.Clob类型,包含了用户的简历信息,当咱们加载该方针时,咱们不得不每一次都要加载这个字段,而不论咱们是不是真的需求它,并且这种大数据方针的读取自身会带来很大的功用开支。在Hibernate2中,咱们只要经过咱们前面讲过的面功用的粒度细分,来分化User类,来解决这个疑问(请参照那一节的论述),可是在Hibernate3中,咱们能够经过特点推迟加载机制,来使咱们获得只要当咱们真实需求操作这个字段时,才去读取这个字段数据的才能,为此咱们有必要如下装备咱们的实体类:
……
经过对元素的lazy特点设置true来敞开特点的推迟加载,在Hibernate3中为了完结特点的推迟加载,运用了类增强器来对实体类的Class文件进行强化处置,经过增强器的增强,将CGLIB的回调机制逻辑,参加实体类,这儿咱们能够看出特点的推迟加载,仍是经过CGLIB来完结的。CGLIB是Apache的一个开源工程,这个类库能够操作java类的字节码,依据字节码来动态结构契合要求的类方针。依据上面的装备咱们运转下面的代码:
String sql=”from User user where user.name=’zx’ ”;
Query query=session.createQuery(sql); (1)
List list=query.list();
for(int i=0;i User user=(User)list.get(i);
System.out.println(user.getName());
System.out.println(user.getResume()); (2)
}
当履行到(1)处时,会生成相似如下的SQL句子:
Select id,age,name from user where name=’zx’;
这时Hibernate会检索User实体中一切非推迟加载特点对应的字段数据,当履行到(2)处时,会生成相似如下的SQL句子:
Select resume from user where id=’1’;
这时会建议对resume字段数据真实的读取操作。
---------------------------------
推迟加载的方针:
hibernate 2对于实体方针和调集
hibernate 3一起供给了特点的推迟加载功用。
其间对调集的推迟加载特性含义最为严重。
实体方针的推迟加载:
1.在hibernate装备文件中的class指定
调集类型的推迟加载:
在set中指定lazy=true
这样只要实践加载与方针相相关的调集方针的时分,再经过session从数据库中加载实践的数据集。
Hibernate.initialize办法能够强制Hibernate当即加载相关的方针集,例如:
Hibernate.initialize(user.getAddress());
调集类型的缓存:
假如为某个调集类设定了缓存,如
name="address"
table="t_address"
lazy="true"
......
>
Hibernate对调集类型进行缓存的时分,分两有些保留。首先是这个调集中一切实体的id列表,其次才是各个实体方针。
这儿制定了cache usage="read-only"只会使得Hibernate对数据索引进行缓存。也即是说只缓存了调集中的数据索引,并不包含调集中的各个实体元素。
假如指定cache usage="read-write"才会对调集中的实体进行缓存。
特点的推迟加载:
在property节点中声明lazy=true,并且还需求凭借Hibernate类增强器对POJO类的二进制Class文件进行强化处置。
hibernate的推迟加载通用办法
public class HibernateUtil extends HibernateDaoSupport {
//用法:instance = getHibernateTemplate().find("from FxjlbVO");
// super.initialize(instance, "getFxjlbChjs");
public void initialize(Object object, String methodName)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
String[] methodArray = methodName.split("/.");
Method method = null;
Object initializeObject = object;
if (methodArray.length == 1) {
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
method = object.getClass()
.getMethod(methodArray[0], new Class[] {});
initializeObject = method.invoke(initializeObject, new Object[] {});
this.getHibernateTemplate().initialize(initializeObject);
} else {
for (int i = 0; i < methodArray.length; i++) {
method = initializeObject.getClass().getMethod(methodArray[i],
new Class[] {});
initializeObject = method.invoke(initializeObject,
new Object[] {});
}
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
public void initialize(Object object, String methodName[])
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
for (int i = 0; i < methodName.length; i++) {
String[] methodArray = methodName[i].split("/.");
Method method = null;
Object initializeObject = object;
if (methodArray.length == 1) {
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
method = object.getClass().getMethod(methodArray[0],
new Class[] {});
initializeObject = method.invoke(initializeObject,
new Object[] {});
//等价于:initializeObject=PropertyUtils.getProperty(initializeObject,methodArray[0]);
this.getHibernateTemplate().initialize(initializeObject);
} else {
for (int j = 0; j < methodArray.length; j++) {
method = initializeObject.getClass().getMethod(
methodArray[j], new Class[] {});
initializeObject = method.invoke(initializeObject,
new Object[] {});
}
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
}
// fInitializeFields是调调集,不是办法名
//instance = getHibernateTemplate().find("from FxjlbVO");
// HashSet aa=new HashSet();
// aa.add("fxjlbChjs");
// super.initialize(instance, aa);
public void initialize(Object object, HashSet fInitializeFields)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
String[] methodName = new String[fInitializeFields.size()];
methodName = (String[]) fInitializeFields.toArray(methodName);
for (int i = 0; i < methodName.length; i++) {
String[] methodArray = methodName[i].split("/.");
Method method = null;
- indexRead arguments from command-line "http://www.shoudashou.com"
- indexRead arguments from command-line "http://www.4lunwen.cn"
- indexRead arguments from command-line "http://www.zx1234.cn"
- indexRead arguments from command-line "http://www.penbar.cn"
- indexRead arguments from command-line "http://www.whathappy.cn"
- indexRead arguments from command-line "http://www.lunjin.net"
- indexRead arguments from command-line "http://www.ssstyle.cn"
- indexRead arguments from command-line "http://www.91fish.cn"
- indexRead arguments from command-line "http://www.fanselang.com"
Object initializeObject = object;
if (methodArray.length == 1) {
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
initializeObject=PropertyUtils.getProperty(initializeObject,methodArray[0]);
this.getHibernateTemplate().initialize(initializeObject);
} else {
for (int j = 0; j < methodArray.length; j++) {
initializeObject=PropertyUtils.getProperty(initializeObject,methodArray[0]);
}
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
}
public void initialize(Collection collection, HashSet fInitializeFields)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
for (Iterator i = collection.iterator(); i.hasNext();) {
Object object = i.next();
this.initialize(object, fInitializeFields);
}
}
public void initialize(Object object) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
this.getHibernateTemplate().lock(object, org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(object);
}
public void initialize(Collection collection, String methodName[])
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
for (Iterator i = collection.iterator();i.hasNext(); ) {
Object object = i.next();
this.initialize(object, methodName);
}
}
Hibernate的强制加载策略