您的位置:首页 > 其它

Hibernate总结3

2010-02-24 21:43 120 查看
实例状态:
PO的三个状态:瞬态,持久化,脱管(离线)

1、(瞬态)未被持久化的VO
此时就是一个内存对象VO,由JVM管理生命周期

2、(持久化)已被持久化的PO,并且在Session生命周期内
此时映射数据库数据,由数据库管理生命周期

3、(脱管)曾被持久化过,但现在和Session已经detached了,以VO的身份在运行
这种和Session已经detached的PO还能够进入另一个Session,继续进行PO状态管理,此时它就成为PO的第二种状态了。这种PO实际上是跨了Session进行了状态维护的。

在传统的JDO1.x中,PO只有前面两种状态,一个PO一旦脱离PM,就丧失了状态了,不再和数据库数据关联,成为一个纯粹的内存VO,它即使进入一个新的PM,也不能恢复它的状态了。

Hibernate缓存介绍:
缓存在Hibernate中主要有三个方面:一级缓存、二级缓存和查询缓存。
一级缓存
Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,也就是当Session关闭的时候该Session所管理的一级缓存也会立即被清除,所以也可以理解为一级缓存是session缓存。
Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置。
一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储的,在访问的时候使用的是主关键字ID。
虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。Session中所提供的干预方法包括以下两种。
● evict() :用于将某个对象从Session的一级缓存中清除。
● clear() :用于将一级缓存中的对象全部清除。
在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。具体的实现方法如清单14.8所示。
清单14.8 大批量更新时缓存的处理方法
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(……);
session.save(customer);
if ( i % 20 == 0 ) {
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
}
tx.commit();
session.close();

Hibernate查询方法与缓存的关系

在前面介绍了Hibernate的缓存技术以及基本的用法,在这里就具体的Hibernate所提供的查询方法与Hibernate缓存之间的关系做一个简单的总结。
在开发中,通常是通过两种方式来执行对数据库的查询操作的。一种方式是通过ID来获得单独的Java对象,另一种方式是通过HQL语句来执行对数据库的查询操作。下面就分别结合这两种查询方式来说明一下缓存的作用。
通过ID来获得Java对象可以直接使用Session对象的load()或者get()方法,这两种方式的区别就在于对缓存的使用上。
● load()方法
在使用了二级缓存的情况下,使用load()方法会在二级缓存中查找指定的对象是否存在。
在执行load()方法时,Hibernate首先从当前Session的一级缓存中获取ID对应的值,在获取不到的情况下,将根据该对象是否配置了二级缓存来做相应的处理。
如配置了二级缓存,则从二级缓存中获取ID对应的值,如仍然获取不到则还需要根据是否配置了延迟加载来决定如何执行,如未配置延迟加载则从数据库中直接获取。在从数据库获取到数据的情况下,Hibernate会相应地填充一级缓存和二级缓存,如配置了延迟加载则直接返回一个代理类,只有在触发代理类的调用时才进行数据库的查询操作。
在Session一直打开的情况下,并在该对象具有单向关联维护的时候,需要使用类似Session.clear(),Session.evict()的方法来强制刷新一级缓存。
● get()方法
get()方法与load()方法的区别就在于不会查找二级缓存。在当前Session的一级缓存中获取不到指定的对象时,会直接执行查询语句从数据库中获得所需要的数据。
在Hibernate中,可以通过HQL来执行对数据库的查询操作。具体的查询是由Query对象的list()和iterator()方法来执行的。这两个方法在执行查询时的处理方法存在着一定的差别,在开发中应该依据具体的情况来选择合适的方法。
● list()方法
在执行Query的list()方法时,Hibernate的做法是首先检查是否配置了查询缓存,如配置了则从查询缓存中寻找是否已经对该查询进行了缓存,如获取不到则从数据库中进行获取。从数据库中获取到后,Hibernate将会相应地填充一级、二级和查询缓存。如获取到的为直接的结果集,则直接返回,如获取到的为一些ID的值,则再根据ID获取相应的值(Session.load()),最后形成结果集返回。可以看到,在这样的情况下,list()方法也是有可能造成N次查询的。
查询缓存在数据发生任何变化的情况下都会被自动清空。
● iterator()方法
Query的iterator()方法处理查询的方式与list()方法是不同的,它首先会使用查询语句得到ID值的列表,然后再使用Session的load()方法得到所需要的对象的值。
在获取数据的时候,应该依据这4种获取数据方式的特点来选择合适的方法。在开发中可以通过设置show_sql选项来输出Hibernate所执行的SQL语句,以此来了解Hibernate是如何操作数据库的。

Hibernate:乐观锁,悲观锁。
悲观锁:是基于数据库锁的机制实现的,只支持单个事务的操作,有一个事务在操作时别的事务操作就不能进行。
session.load(Person.class, "ID", LockMode.UPGRADE);
乐观锁:支持多个事务操作。是采用数据库版本机制实现的
<class name="包名.类名" table="表名" optimistic-lock="version">
<id name="id">
<generator class="uuid.hex" />
</id>
<version name="version"/>
<property name="属性名" />
</class>
注:version在数据进行更改时会自动加一

使用hibernate 操作oracle:
Hibernate连接Oracle数据库的步骤
hibernate.cfg.xml需要改动两处地方
1. 数据库连接驱动::oracle.jdbc.driver.OracleDriver
2. 方言:org.hibernate.dialect.OracleDialect

Hibernate 原始sql的另一种查询方法命名查询<sql-query name="persons">
<return alias="person" class="erson"/>
SELECT
person.person_id AS {person.id},
person.NAME AS {person.name},
person.AGE AS {person.age}

FROM PERSON person
</sql-query>
Hibernate调用Oracle函数 <sql-query name="名字" callable="true">
<return alias="person" class="erson">
<return-property name="id" column="person_id"/>
<return-property name="name" column="name"/>
<return-property name="age" column="age"/>
</return>
{?=call oracle函数名()}
</sql-query>
Hibernate的事务:
Hibernate 是JDBC 的轻量级封装,本身并不具备事务管理能力。在事务管理层,
Hibernate将其委托给底层的JDBC或者JTA,以实现事务管理和调度功能。
Hibernate的默认事务处理机制基于JDBC Transaction。

抓取策略:连接.查询.子查询.批量
1.连接抓取(Join fetching) - Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来获得对象的关联实例或者关联集合。一个对象一条SQl语句.
<set name="students" inverse="true" cascade="all" fetch="join">
<key column="classid" />
<one-to-many class="com.Student" />
</set>

Classes cla = (Classes)session.load(Classes.class,1);
System.out.println(cla.getName());
for(Iterator iter = cla.getStudents().iterator();iter.hasNext();){
Student student = (Student)iter.next();
System.out.println(student.getName());
}
Fetch=”join” ,上面程序只发了一条sql语句.

2.查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。在上面的程序中会发出当前对象关联的集合的大小+1条sql语句.

3.子查询抓取(Subselect fetching) - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条
select语句。所有最多只会发出两条SQL语句. 如果只有一个对对象则Join与Subselect没有区别.如果是多个则Join查询次数为对象的个数而Subselect则只有一条sql语句.

4.批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT语句获取一批对象实例或集合。
<set name="students" inverse="true" cascade="save-update" batch-size=”3”>
List students = session.createQuery(“select s from Student s where s.id in(1,2,3,4,5,6,7,8).list();
for(Iterator iter=students.iterator();iter.hasNext();){
Student student = (Sutdent)iter.next();
System.out.println(student.getName());
System.out.println(student.getClassess().getName());
}
当第二个for循环时,每次加载 之前设置的 数量 实体对象, 如:现在设置3,那么当
Iterator iter=students.iterator();
iter.hasNext();时候,他会查询出3个student对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: