tfboys自然堂照片:结果集的用处

来源:百度文库 编辑:杭州交通信息网 时间:2024/04/29 04:54:36

我们已经为您展示了如何在对集合持久化时使用延迟装载(lazy initialization)。对于通常的对象引用,使用CGLIB代理可以达到类似的效果。我们也提到过Hibernate在Session级别缓存持久化对象。还有更多先进的缓存策略,你可以为每一个类单独配置。

这一章里,我们来教你如何使用这些特性,在必要的时候得到高得多的性能。

12.1. 用于延迟装载的代理
Hibernate使用动态字节码增强技术来实现持久化对象的延迟装载代理(使用优秀的CGLIB库)。

映射文件为每一个类声明一个类或者接口作为代理接口。建议使用这个类自身:

<class name="eg.Order" proxy="eg.Order">
运行时的代理应该是Order的子类。注意被代理的类必须实现一个默认的构造器,并且至少在包内可见。

在扩展这种方法来对应多形的类时,要注意一些细节,比如:

<class name="eg.Cat" proxy="eg.Cat">
......
<subclass name="eg.DomesticCat" proxy="eg.DomesticCat">
.....
</subclass>
</class>
首先,Cat永远不能被强制转换为DomesticCat,即使实际上该实例就是一个DomesticCat实例。

Cat cat = (Cat) session.load(Cat.class, id); // instantiate a proxy (does not hit the db)
if ( cat.isDomesticCat() ) { // hit the db to initialize the proxy
DomesticCat dc = (DomesticCat) cat; // Error!
....
}
其次,代理的==可能不再成立。

Cat cat = (Cat) session.load(Cat.class, id); // instantiate a Cat proxy
DomesticCat dc =
(DomesticCat) session.load(DomesticCat.class, id); // required new DomesticCat proxy!
System.out.println(cat==dc); // false
虽然如此,这种情况并不像看上去得那么糟。虽然我们现在有两个不同的引用来指向不同的代理对象,实际上底层的实例应该是同一个对象:

cat.setWeight(11.0); // hit the db to initialize the proxy
System.out.println( dc.getWeight() ); // 11.0
第三,你不能对final的类或者具有final方法的类使用CGLIB代理。

最后,假如你的持久化对象在实例化的时候需要某些资源(比如,在实例化方法或者默认构造方法中),这些资源也会被代理需要。代理类实际上是持久化类的子类。

这些问题都来源于Java的单根继承模型的天生限制。如果你希望避免这些问题,你的每个持久化类必须抽象出一个接口,声明商业逻辑方法。你应该在映射文件中指定这些接口,比如:

<class name="eg.Cat" proxy="eg.ICat">
......
<subclass name="eg.DomesticCat" proxy="eg.IDomesticCat">
.....
</subclass>
</class>
这里Cat实现ICat接口,并且DomesticCat实现IDomesticCat接口。于是 load()或者iterate()就会返回Cat和DomesticCat的实例的代理。(注意find()不会返回代理。)

ICat cat = (ICat) session.load(Cat.class, catid);
Iterator iter = session.iterate("from cat in class eg.Cat where cat.name='fritz'");
ICat fritz = (ICat) iter.next();
关系也是延迟装载的。这意味着你必须把任何属性声明为ICat类型,而非Cat。

某些特定操作不需要初始化代理

equals(), 假如持久化类没有重载equals()

hashCode(), 假如持久化类没有重载hashCode()

标识符的get方法

Hibernate会识别出重载了equals() 或者 hashCode()方法的持久化类。

在初始化代理的时候发生的异常会被包装成LazyInitializationException。

有时候我们需要保证在Session关闭前某个代理或者集合已经被初始化了。当然,我们总是可以通过调用cat.getSex()或者 cat.getKittens().size()之类的方法来确保这一点。但是这样程序可读性不佳,也不符合通常的代码规范。静态方法Hibernate.initialize()和Hibernate.isInitialized()给你的应用程序一个正常的途径来加载集合或代理。Hibernate.initialize(cat) 会强制初始化一个代理,cat,只要它的Session仍然打开。Hibernate.initialize( cat.getKittens() )对kittens的集合具有同样的功能。

12.2. 第二层缓存(The Second Level Cache)s
HibernateSession是事务级别的持久化数据缓存。再为每个类或者每个集合配置一个集群或者JVM级别(SessionFactory级别)的缓存也是有可能的。你