java框架hibernate如何取消自动更新持久化层的对象状态状态的对象?

ssh框架,Action里的取出对象,用set方法更新一个字段,然后调用Service里的一个事务性方法,方法体为空,但Hibernate却更新了数据库????
[问题点数:20分]
ssh框架,Action里的取出对象,用set方法更新一个字段,然后调用Service里的一个事务性方法,方法体为空,但Hibernate却更新了数据库????
[问题点数:20分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。Hibernate入门04-Hibernate中Java对象的三种状态_Java教程_
Hibernate入门04-Hibernate中Java对象的三种状态
来源:人气:93
目录:(后续不断更新...)
Hibernate 入门 01 - 框架技术 (介绍Hibernate框架的发展由来)
Hibernate 入门 02 - Hibernate介绍及其环境搭建
Hibernate 入门 03 - 使用Hibernate完成持久化操作
Hibernate 入门 04 - Hibernate中对象的三种状态
&▁▃▅&Hibernate中Java对象的三种状态▅▃▁
1. Java对象的三种状态
  当应用通过调用Hibernate API与框架发生交互时,需要从持久化的角度关注应用对象的生命周期。
  持久化声明周期是Hibernate中的一个关键概念,正确地理解生命周期,可以更好地了解Hibernate的实现原理,掌握Hibernate的正确用法。
  Hibernate框架通过来管理Java对象的状态,在持久化生命周期中,Java对象存在着如下三种状态:
瞬时状态(Transient)
  通过new创建对象后,对象并没有like持久化,它并未与中的数据有任何关联,此时Java对象的状态为瞬时状态。
  Session对于瞬时状态的Java对象是一无所知的,当对象不再被其他对象引用时,它的所有数据也就丢失了,对象将会被Java虚拟机按照垃圾回收机制处理。
持久状态(Persistent)
  当对象与Session关联,被Session管理时,它就处于持久状态。处于持久状态的对象拥有数据库标识(数据库中的主键值)。
  那么,对象是什么时候与Session发生关联的呢?有两种方法:
    第一种,通过Sesison的查询接口,或者get()方法,或者load()方法从数据库中加载对象的时候,加载的对象是与数据库表中的一条记录关联的,此时对象与加载它的Session发生关联;
    第二种,瞬时状态的对象,通过Session的save()方法或SaveOrUpdate()方法时,Java对象也与Session发生关联。
  对于处于持久状态的对象,Session会持续跟踪和管理它们,如果对象的内部状态发生了任何变更,Hibernate会选择合适的时机(如事务提交时)将变更固化到数据库中。
  处于持久状态的对象,脱离与其关联的nSession的管理后,对象就处于游离状态。
  处于游离状态的对象,Session无法保证对象所包含的数据与数据库中的记录一直,因为Hibernate已经无法感知对该对象的任何操作。
  Session提供了两个方法(update()、merge()),将处于游离状态的对象,与一个新的Session发生关联。
  此时,对象的状态就从游离状态重新转换为持久状态。
2. 三种状态之间的转换
  在Hibernate应用中,不同的持久化操作会导致对象状态的改变。如图描述了对象状态的转换:
  使用new关键字构建对象,该对象的状态是瞬时状态。
2.1 瞬时状态转为持久状态
  使用Session对象的save()或saveOrUpdate()方法保存对象后,该对象的状态由瞬时状态转换为持久状态。
  使用Session对象的get()或load()方法获取对象,该对象的状态是持久状态。
2.2 持久状态转为瞬时状态
  执行Session对象的delete()方法后,对象由原来的持久状态变为瞬时状态,因为此时该对象没有与任何的数据库数据关联。
2.3 持久状态转为游离状态
  吃行了Session对象的evict()、clear()或close()方法,对象由原来的持久状态转为游离状态。
2.4 游离状态转为持久状态
  重新获取Session对象,执行Session对象的update()或saveOrUpdate()方法,对象由游离状态转为持久状态,该对象再次与Session对象相关联。
2.5 游离状态转为瞬时状态
  执行Session对象的delete()方法,对象由游离状态转为瞬时状态。
  处于瞬时状态或游离状态的对象不再被其他对象引用时,会被Java虚拟机按照垃圾回收机制处理。
3. 练习(好记性不如烂键盘) - 输出对象的状态
  需求:为以下两段代码补充语句,输出各个阶段对象的状态。
  代码1:
// 省略部分代码...
session = sessionFactory.openSession();
tx = session.beginTransaction();
// 开始一个事务
User user = (User)session.load(User.class, new Integer("1001"));
// 获取用户对象
user.setUsername("张董");
// 修改用户信息
tx.commit();
// 提交事务
8 }catch(HibernateException e){
e.intStackTrace();
tx.rollback();
// 回滚事务
11 }finally{
if(null != session){
session.close();
// 关闭session
  代码2:
// 省略部分代码
session = sessionFactory.openSession();
// 打开session
tx = session.beginTransaction();
// 开始一个事务
User user = (User)session.load(User.class, new Integer("1000"));
// 获取User对象
session.delete(user);
// 持久化操作 - 删除
tx.commit();
// 提交事务
8 }catch(HibernateException e){
e.printStackTrace();
tx.rollback();
// 回滚事务
11 }finally{
if(null != session){
session.close();
// 关闭session
优质网站模板hibernate 深入理解持久化对象
hibernate 完全采用面向对象的方式来操作,因此开发者眼里只有对象、属性,无须理会数据库、表、列等概念。
持久化类的要求
Hibernate 采用低侵入式设计,所以对持久化类的要求也是只要是简单的pojo即可。
虽然hibernate对持久化没什么要求,但应遵守如下规则:
-提供一个无参的构造器,这样hibernate就可以使用Constructor.newInstance()来创建持久化实例了。
-提供 一个标识属性,通常是映射数据库的主键字段
-对象的属性应尽量避免使用最基本的类型,如int 采用integer代替。
-为持久化类的每个成员变量提供getter和setter方法。
-使用非final的类,在运行时生成代理是Hibernate的一个重要功能
-重写equals和hashcode方法,如果需要把持久化类放入set中。
持久化对象的状态
瞬态:对象由new操作符创建,且尚未与hibernate Session关联的对象被 认为处于瞬态。
持久化:持久化实例在数据库中有对应的记录,并拥有一个持久化标识identifier。在当前操作执行完成时将对象 数据写回数据库。开发者不需要手动执行update
脱管:某个实例曾经处于持久化状态,但随着与之关联的Session被关闭,该对象将变成持久化状态
改变持久化对象状态的方法
-Serializable save(object obj)将对象变为持久化状态
-void persist(object obj)将对象转化为持久化状态
-Serializable save(object obj,object pk)将obj对象转化为持久化状态,该对象保存到数据库,指定主键值
-void persist(object obj,object pk) 也加了一个设定主键
save和persist方法的区别:使用save保存持久化对象时会返回 该 持久化对象的标识属性值。这就可以用到下面的方法中
根据主键加载持久化实体
News n=sess.load(News.class,pk);
如果没有匹配的数据库记录会抛出hibernateExpetion异常,如果在持久化类注解中指定了延迟加载,则load方法会返回 一个未初始化的代码对象,但它并没有加载数据 ,直到程序调用该对象的某个方法里。hibernate才会访问数据库
与load方法类似的是get方法,区别 就是get方法会立刻访问数据库,如果没有对应的记录,get方法会返回 Null,而不是返回一个代理对象。
更新持久化实体
u.setUserName("");
sess.flush();
更新托管实体
对于一个曾经持久化过,但已经了session管理 的持久化对象,被认为处于脱管状态,此时程序应该显式的使用新的Session来保存修改。hibernate提供了三个方法update merge saveorupdate
当需要使用Update方法来更新修改时,如果不记得该对象是否持久化过,可以使用saveorupdate方法,如果持久化过会使用upate方法,否则是save方法。
merge方法与update方法功能相同 ,区别执行sess.merge(a)方法后,a对象不是持久化对象的状态。而Update会把a变成持久化对象。
Session sess = sf.openSession();
org.hibernate.Transaction tx = sess.beginTransaction();
User u=(User) sess.load(User.class, 2);
System.out.println(u.getUserName());
tx.commit();
sess.close();
Session sess2 = sf.openSession();
org.hibernate.Transaction tx2 = sess2.beginTransaction();
u.setUserName("");
sess2.saveOrUpdate(u);
sf.close();
删除持久化实体
sess2.delete(u);
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Hibernate 持久化对象-中国学网-中国IT综合门户网站-提供健康,养生,留学,移民,创业,汽车等信息
> 信息中心 >
Hibernate 持久化对象
来源:互联网 发表时间: 9:35:45 责任编辑:李志喜字体:
为了帮助网友解决“Hibernate 持久化对象”相关的问题,中国学网通过互联网对“Hibernate 持久化对象”相关的解决方案进行了整理,用户详细问题包括:假如我new了 一个User session.save(user); 但是我没有c俯辅碘恍鄢喝碉桶冬垃ommit() 这时候的对象 也是一个持久化对象吗,具体解决方案如下:解决方案1:
在没有commit之前,对象不会保存到数据库中,自然不会是持久化对象了
提问者评价
解决方案2:
没错,在hibernate中。。。。。。这样容易报错
相关文章:
最新添加资讯
24小时热门资讯
Copyright © 2004- All Rights Reserved. 中国学网 版权所有
京ICP备号-1 京公网安备02号java Hibernate框架Session的保存、更新、删除和查询教程 | 一聚教程网
java Hibernate框架Session的保存、更新、删除和查询教程
session的save方法使一个临时对象变为持久化对象。session的save方法完成以下操作:1、把customer对象加入到缓存中,使他变为持久化对象2、选用映射文件指定的标识符生成器为持久化对象分配唯一的OID。Customer.hbm.xml文件中id元素的子元素指定标识符生成器:&&& 在配置文件配置了id自增后,在程序中在setId();是无效的。3、计划执行一个insert语句,把customer对象当前的属性组装到insert语句中,save方法并不会立即执行sql语句。只有当清理缓存时才会执行insert语句。如果在save方法之后又修改了持久化对象的属性,这会使得Session在清理缓存的时候额外执行Sql 的update语句。以下两段代码尽管都能完成相同功能,第一段代码仅执行了一条insert语句,而右边执行了一条insert语句和一条update语句。第一段代码减少了数据库访问次数,具有更好的性能。Customer customer = new Customer();// 先设置customer属性再保存customer.setName("Tom");session.save(customer);tx.commit();Customer customer = new Customer();session.save(customer);// 先保存再设置customer属性customer.setName("Tom");tx.commit();Hibernate通过持久化对象的OID来维持他和数据库相关记录的对应关系。当Customer对象处于持久化状态时,不允许随意修改他的OID。session的update方法使一个游离对象转变为持久化对象session的update方法完成以下操作:1、把Customer对象重新加入到Session缓存中,使他变为持久化对象2、计划执行一个update语句。值得注意的是session只在清理缓存的时候执行update只要通过update方法使游离对象被一个Session关联,即使没有修改Customer对象的任何属性,Session在清理缓存时也会执行由update方法计划的update语句。如果希望session仅仅当修改了Customer对象的属性时才执行update语句,可以把映射文件中class元素的select-before-update设为true,默认为false; 当update方法关联一个游离对象时,如果在session缓存中已经存在相同的OID的持久化对象,会抛出异常。session的saveOrUpdate方法saveOrUpdate方法同时包含了save与update方法,如果传入的参数是临时对象,就调用save方法,如果传入的是游离对象就调用update方法,如果传入的是持久化对象就直接返回。那么Hibernate如何判断对象的状态呢?下面看看临时对象的判断条件:1、Java对象的OID取值为null2、Java对象具有version属性并且取值为null3、在映射文件中为id元素设置了unsaved-value属性,并且OID取值与unsaved-value属性值匹配4、在映射文件中为version属性设置了unsaved-value属性,并且OID取值与unsaved-value属性值匹配5、自定义了Hibernate的Interceptor实现类,并且Interceptor的isUnsaved方法返回truesession的load和get方法Session的load和get方法都能根据OID从数据库中加载一个持久化对象,区别在于:当数据库中没有与之对应的记录时load方法会抛出ObjectNotFoundException异常,get方法返回null。get方法会在调用之后立即向数据库发出sql语句(不考虑缓存的情况下),返回持久化对象;而load方法会在调用后返回一个代理对象,该代理对象只保存了实体对象的id,直到使用对象的非主键属性时才会发出sql语句Session的delete方法delete方法用于从数据库中删除与Java对象对应的记录,如果传入的参数是持久化对象,session就计划执行一个delete语句,如果传入的是游离对象,先使游离对象被session关联,使他变为持久化对象,然后计划执行一个delete语句。Session只有在清理缓存的时候才会执行delete语句,只有调用session.close才会从session缓存中删除对象。hibernate的Session操作, 查询过滤, 缓存利用, 批量处理一. Session操作, 查询过滤, 缓存利用, 批量处理数据查询,装载1.&& Session---单数据加载---load/ getLoad方法根据指定的实体类和id从数据库装载认为存在的一条记录. 应该确保对象确实存在, 否则会抛出ObjectNotFoundException.Load方法可返回实体的代理类实例, 可充分利用内部缓存和二级缓存中的现有数据.&get方法根据指定的实体类和id从数据库查询并装载一条记录.数据不存在将得到null.get方法返回的永远是实体类. 只在内部缓存中进行数据查找, 如果没有数据就调用SQL完成数据读取.&&&& 出于性能考虑,避免无谓的数据库访问,Session在调用数据库查询功能之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,如果第一级缓存查找命中,且数据状态合法,则直接返回。&&& 之后,Session会在当前 “NonExists”记录中进行查找,如果 “NonExists”记录中存在同样的查询条件,则返回null。“NonExists”记录了当前 Session实例在之前所有查询操作中,未能查询到有效数据的查询条件。如果Session中一个无效的查询条件重复出现,即可迅速做出判断。&&& 对于load方法而言,如果内部缓存中没有发现有效数据,则查询第二级缓存,如果第二级缓存命中,则返回。&&& 如果在缓存中未发现有效数据,则发起数据库查询操作(Select SQL).&&& 如果经过查询未发现对应记录,则将此次查询的信息在 “NonExists”中加以记录,并返回null。&&& 否则根据映射配置和Select SQL得到的 ResultSet,创建对应的数据对象. 并将其数据对象纳入当前Session实体管理容器(一级缓存)。&&& 执行Interceptor.onLoad方法(如果有对应的Intercepeor)。&&& 将数据对象纳入二级缓存。&&& 如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad方法。&&& 返回数据对象。2.&& Session---批量数据查询---find/iterate|createQuery().list/iterateHibernate2的find/iterate分别返回list和Iterator, Hibernate3中,上述方法已经从Session接口中废除,统一由Query接口提供。Hibernate3将Session的createQuery()方法得到的Query对象调用list/iterate方法实现相同的功能. 从实现体制而言,这两个版本之间并没有什么差异。&find/ list方法通过一条select sql实现查询; 而iterate则执行1+ N次查询, 它首先执行select sql获取满足条件的id, 再根据每个id获取对应的记录.find方法将执行Select HQL从数据库中获得所有符合条件的记录并构造相应的实体对象,实体对象构建完毕之后,就将其纳入缓存。为之后的iterate方法提供了现成的可用数据。这样,之后iterate方法执行时,它首先执行一条Select SQL以获得所有符合查询条件的数据id,随即,iterate方法首先再本地缓存中根据id查找对应的实体对象是否存在(类似Session.load方法),如果缓存中已经存在对应的数据,则直接以此数据对象作为查询结果,如果没找到,再执行相应的Select语句获得对应的库表记录(iterate方法如果执行了数据库读取操作并构建了完整的数据对象,也会将其查询结果纳入缓存)。&根据java面向对象的继承层次,Object是所有类的父类,所以使用面对对象的持久化框架Hibernate可以执行下述操作:&&& public static void testHibernateOO() {&&&&&& Session s = HibernateSession3.getSession();&&&&&& Iterator itor =(Iterator)s.createQuery("FROM java.lang.Object").list();&&&&&& while(itor.hasNext()){&&&&&&&&&& Object rowData =& itor.next();&&&&&&&&&& System.out.println(rowData.getClass()+":");&&&&&& }&&& }3.&& Session批量数据查询与缓存利用的示例如果执行下面的代码:Tuser data =Iterator dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:AiSee1, 1w@11, ]Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]&如果执行下面的代码:Tuser data =&&&&&& List datas = hibernate_session.createQuery(" From Tuser").list();&&&&&& for(int i=0;i<datas.size();i++){&&&&&&&&&& data = datas.get(i);&&&&&&&&&& System.out.println("list:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&&&& System.out.println("\r\nUse iterate");&&& Iterator dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user tuser0_list:AiSee1, 1w@11, ]list:Washing:[]&Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_iterate:AiSee1, 1w@11, ]iterate:Washing:[]如果执行下面的代码:&&&&&&& Tuser data =&&&&&& List datas = hibernate_session.createQuery(" From Tuser").list();&&&&&& for(int i=0;i<datas.size();i++){&&&&&&&&&& data = datas.get(i);&&&&&&&&&& System.out.println("list:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&&&& System.out.println("\r\nUse iterate");&&& Iterator dataItor = hibernate_session.createQuery(" From Tuser"). iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&& &&&&&&& System.out.println("\r\nUse list AGAIN");&&&&&& datas = hibernate_session.createQuery(" From Tuser").list();&&&&&& for(int i=0;i<datas.size();i++){&&&&&&&&&& data = datas.get(i);&&&&&&&&&& System.out.println("list:" + data.getName() + ":" + data.getEmail());&&&&&& }Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user tuser0_list:AiSee1, 1w@11, ]list:Washing:[]&Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_iterate:AiSee1, 1w@11, ]iterate:Washing:[]&Use list AGAINHibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user tuser0_list:AiSee1, 1w@11, ]list:Washing:[]&Use listHibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user tuser0_list:AiSee1, 1w@11, ]list:Washing:[]如果执行:Tuser data =&&&&&& System.out.println("\r\nUse list");&&&&&& List datas = hibernate_session.createQuery(" From Tuser").list();&&&&&& for(int i=0;i<datas.size();i++){&&&&&&&&&& data = datas.get(i);&&&&&&&&&& System.out.println("list:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&&&& hibernate_session.close();&&&&&& hibernate_session = MySessionFactory.getSession();&&&& &&&&&&&& System.out.println("\r\nUse iterate");&&& Iterator dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&& &&&&&&& System.out.println("\r\nUse list AGAIN");&&&&&& datas = hibernate_session.createQuery(" From Tuser").list();&&&&&& for(int i=0;i<datas.size();i++){&&&&&&&&&& data = datas.get(i);&&&&&&&&&& System.out.println("list:" + data.getName() + ":" + data.getEmail());&&&&&& }&Use listHibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user tuser0_list:AiSee1, 1w@11, ]list:Washing:[]&Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:AiSee1, 1w@11, ]Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]&Use list AGAINHibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user tuser0_list:AiSee1, 1w@11, ]list:Washing:[]如果执行下面的代码:System.out.println("\r\nUse iterate");Iterator dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&& &&&&&&& System.out.println("\r\nUse iterate AGAIN");&&&&&& dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:AiSee1, 1w@11, ]Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]&Use iterate AGAINHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_iterate:AiSee1, 1w@11, ]iterate:Washing:[]如果执行下面的代码:System.out.println("\r\nUse iterate");Iterator dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&& &&&&&&& hibernate_session.close();&&&&&& hibernate_session = MySessionFactory.getSession();&&&&&& System.out.println("\r\nUse iterate AGAIN");&&&&&& dataItor = hibernate_session.createQuery(" From Tuser").iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:AiSee1, 1w@11, ]Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]&Use iterate AGAINHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:AiSee1, 1w@11, ]Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]&find方法(hibernate2)/Query的list(hibernate3)实际上不利用缓存,它对缓存只写不读。而iterate方法(hibernate2)/Query的iterate(hibernate3)则可以充分发挥缓存带来的优势,如果目标数据只读或者读取相对较为频繁,通过这种机制可以大大减少性能上的损耗。对于批量数据, hibernate可以自动延迟加载:&把数据库数据扩大后:String hsql = " From Tuser as t where t.id<501";&&&&&& Tuser data =&&&& &&&&&&& long end =0;&&&&&& &&&&&&& System.out.println("\r\nUse iterate");& &&&&&&&& long begin =System.currentTimeMillis();&&&&&& Iterator dataItor = hibernate_session.createQuery(hsql).iterate();&&&&&&& end =System.currentTimeMillis();&&&&&& System.out.println("Time be userd:"+(end-begin));&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&& &&Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ where tuser0_.id<501Time be userd:15Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.email as email0_0_ from T_user tuser0_ where tuser0_.id=?iterate:AiSee1, 1w@11, ]Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.email as email0_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.email as email0_0_ from T_user tuser0_ where tuser0_.id=?iterate:Washing:[]....执行:String hsql = " From Tuser as t where t.id<100001";&&&&&& Tuser data =&&&& &&&&&&& System.out.println("\r\nUse list");&&&&&& long end =0;&&&&&&& long begin =System.currentTimeMillis();&&&&& &&&&&&& System.out.println("\r\nUse iterate");& &&&&&&&& begin =System.currentTimeMillis();&&&&&& Iterator dataItor = hibernate_session.createQuery(hsql).iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& //System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&&&&& end =System.currentTimeMillis();&&&&&& System.out.println("Time be userd:"+(end-begin));&&&& &&&&&&& System.out.println("\r\nUse iterate AGAIN");&& &&&&&&&& begin =System.currentTimeMillis();&&&&&& dataItor = hibernate_session.createQuery(hsql).iterate();&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& //System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& }&&&&&&& end =System.currentTimeMillis();&&&&&& System.out.println("Time be userd:"+(end-begin));&Use list&Use iterateHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ where tuser0_.id<100001Time be userd:4078&Use iterate AGAINHibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ where tuser0_.id<100001Time be userd:3797&如果是用list, 不会利用任何缓存,更不会延迟加载:System.out.println("\r\nUse list");&&&&&& long end =0;&&&&&&& long begin =System.currentTimeMillis();&&&&&& List datas = hibernate_session.createQuery(hsql).list();&&&&&&& end =System.currentTimeMillis();&&&&&& System.out.println("Time be userd:"+(end-begin));&&&&&& for(int i=0;i<datas.size();i++){&&&&&&&&&& data = datas.get(i);&&&&&&&&&& System.out.println("list:" + data.getName() + ":" + data.getEmail());&&&&&& }Use listHibernate: select tuser0_.id as id0_, tuser0_.name as name0_, tuser0_.email as email0_ from T_user tuser0_ where tuser0_.id<501Time be userd: 78list:AiSee1, 1w@11, ]list:Washing:[]list:Washing:[]list:Washing:[]list:Washing:[]list:Washing:[]如果数据量较大, 结合iterate方法和Session/SessionFactory的evict方法逐条对记录进行处理,并将数据对象强制从缓存中移除, 将内存消耗保持再可以接受的范围之内。查询50万条:System.out.println("\r\nUse iterate");& &&&&&&&& begin =System.currentTimeMillis();&&&&&& Iterator dataItor = hibernate_session.createQuery(hsql).iterate();&&&& &&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& data.getName();&&&&&&&&&& //System.out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&&&&&& hibernate_session.evict(data);&&&&&&&&&& factory.evict(Tuser.class,data.getId());&&&&&& }&&&&&&& end =System.currentTimeMillis();&&&&&& System.out.println("Time be userd:"+(end-begin));Use iterateTime be userd:2113969直接查询并保存在缓存:System.out.println("\r\nUse iterate");& &&&&&&&& begin =System.currentTimeMillis();&&&&&& Iterator dataItor = hibernate_session.createQuery(hsql).iterate();&&&& &&&&&&& while(dataItor.hasNext()){&&&&&&&&&& data = dataItor.next();&&&&&&&&&& data.getName();&&&&&&&&&& //out.println("iterate:" + data.getName() + ":" + data.getEmail());&&&&&& //& hibernate_session.evict(data);&&&&&& //& factory.evict(Tuser.class,data.getId());&&&&&& }&&&&&&& end =System.currentTimeMillis();&&&&&& System.out.println("Time be userd:"+(end-begin));&&&&&& out.println("Time be userd:"+(end-begin)+"");Use iterateERROR:
20:55:28,687: StandardWrapperValve[line:253}: Servlet.service() for servlet jsp threw exceptionjava.lang.OutOfMemoryError: Java heap space&所以数据量过大, 应该避免使用find(list), 而使用iterate(iterate),并且手动清除hibernate的一,二级缓存。4.&& Query Cache(阑尾)Query Cache中保存了之前查询操作执行过的Select SQL,以及由此查询产生的查询结果集 (包括查询对象的类型和id)。之后发生查询请求的时候,Hibernate会首先根据查询的 SQL从Query Cache中检索,如果此SQL曾经执行过,则取出对应这个SQL的检索结果集,再根据这个结果集中的对象类型及其id,从缓存中取出对应的实体对象返回。Query Cache中缓存的SQL及其结果集并非永远存在,当Hibernate发现此SQL对应的库表发生了变动(Update/Delete/Insert),会自动将Query Cache中对应表的 SQL缓存废除。因此,Query Cache只在特定的情况下产生作用:&&& 完全相同的Select SQL重复执行。&&& 再两次查询之间,此Select SQL对应的库表没有发生过改变。由于以上两个条件的严格限制,Query Cache再实际应用中的意义并没有我们想象中的那么重大,因此,Hibernate在默认情况下也关闭了这个特性。为了启用Query Cache,我们必须在Hibernate配置文件(hibernate.cfg.xml)中打开配置hibernate.cache.use_query_cache为ture,之后我们必须在Query 的查询执行之前, 调用Query的setQureyCache(true); 而且后面的查询想利用该缓存也需要调用Query的setQureyCache(true). 这样find(list)就可以利用Query Cache缓存了.鉴于配置和使用比较麻烦, 所以用得不多.5.&& Hibernate2的find/iterate的批量查询条件find(String) throws HibernateEfind(String, Object, Type) throws HibernateEfind(String, Object[], Type[]) throws HibernateE&iterate(String)iterate(String, Object, Type)iterate(String, Object[], Type[])&其中的字符串参数表示一个可带查询参数的HQL查询字符串, 其中的每个 ? 代表一个参数, 而对应的Object[]参数表示每个?的值, 而Type[]数组代表每个参数的数值类型. 取自net.sf.hibernate.type.Type类的实现. net.sf.hibernate.type包下面有很多XXXType的实现类, 也可以使用net.sf.hibernate.Hibernate类的NullableType类型静态常量属性(表示Type类型的一个实现. 比如Hibernate.STRING表示一个字符串类型).&AddUserForm inData = (AddUserForm)hsql =" From webapp.hibernate.pojo.UserPoJo As user2 Where user2.tel=? and user2.user=?";s.find(hsql,new Object[]{inData.getTel(), inData.getUser()},&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& new Type[]{new net.sf.hibernate.type.StringType(), new net.sf.hibernate.type.StringType()});&/* //或者:&s.find( hsql,new Object[]{ inData.getTel(), inData.getUser() } ,&&&&&&&&& new Type[]{ Hibernate. STRING, Hibernate.STRING } );&*/6.&& Hibernate2/3的Criteria批量查询条件org.hibernate.criterion. Restrictions 及其final子类org.hibernate.criterion.Expression提供了从Criteria对象中增加查询条件的实现.Hibernate3的HQL的查询条件可以用Expression的相关方法.&Criteria criteria = session.createCriteria(Tuser.class);&&& criteria.add(Expression.eq("name", "Erica"));&数据查询与检索是Hibernate中的一个亮点。相对其他ORM实现而言,Hibernate提供了灵活多样的查询机制。其中包括:1. Criteria Query, 2. Hibernate Query Language (HQL), 3. SQL&Criteria Query通过面向对象化的设计,将数据查询条件封装为一个对象。简单来讲,Criteria Query可以看作是传统SQL的对象化表示,如:Criteria criteria = session.createCriteria(TUser.class);criteria.add(Expression.eq("name","Erica"));criteria.add(Expression.eq("sex",new Integer(1)));这里的criteria 实例实际上是SQL “Select * from t_user where name=’Erica’ and sex=1”的封装(我们可以打开Hibernate 的show_sql 选项,以观察Hibernate在运行期生成的SQL语句)。Hibernate 在运行期会根据Criteria 中指定的查询条件(也就是上面代码中通过criteria.add方法添加的查询表达式)生成相应的SQL语句。这种方式的特点是比较符合Java 程序员的编码习惯,并且具备清晰的可读性。正因为此,不少ORM实现中都提供了类似的实现机制(如Apache OJB)。对于Hibernate的初学者,特别是对SQL了解有限的程序员而言,Criteria Query无疑是上手的极佳途径,相对HQL,Criteria Query提供了更易于理解的查询手段,借助IDE的Coding Assist机制,Criteria的使用几乎不用太多的学习。7.&& Criteria 查询表达式, Criterionorg.hibernate.criterion. Expression extends Restrictions,& Restrictions的众多方法对应了SQL的限制条件, 自然也被Expression类继承. (特别地拥有and, or, sql等方法.) 那些方法返回一个Criterion接口的实现, 而这正式Criteria的add方法的参数类型. Criteria 本身只是一个查询容器,具体的查询条件需要通过Criteria.add方法添加到Criteria实例中。Expression 对象具体描述了查询条件。Expression提供了对应的查询限定机制,包括:Expression.eq 对应SQL“field = value”表达式。& 如Expression.eq("name","Erica")Expression.allEq 参数为一个Map对象,其中包含了多个属性-值对应关系。相当于多个Expression.eq关系的叠加。Expression.gt 对应SQL中的 “field > value ” 表达式Expression.ge 对应SQL中的 “field >= value” 表达式Expression.lt 对应SQL中的 “field < value” 表达式Expression.le 对应SQL中的 “field <= value” 表达式Expression.between 对应SQL中的 “between” 表达式如下面的表达式表示年龄(age)位于13到50区间内。Expression.between("age",newInteger(13),new Integer(50));Expression.like 对应SQL中的 “field like value” 表达式Expression.in 对应SQL中的 ”field in …” 表达式Expression.eqProperty 用于比较两个属性之间的值,对应SQL中的“field= field”。如:Expression.eqProperty("TUser.groupID","TGroup.id");Expression.gtProperty 用于比较两个属性之间的值,对应SQL中的“field> field”。Expression.geProperty 用于比较两个属性之间的值,对应SQL中的“field>= field”。Expression.ltProperty 用于比较两个属性之间的值,对应SQL中的“field< field”。Expression.leProperty 用于比较两个属性之间的值,对应SQL中的“field<= field”。Expression.and and关系组合。如:Expression.and(Expression.eq("name","Erica"),Expression.eq("sex",new Integer(1)));Expression.or or关系组合。如:Expression.or(Expression.eq("name","Erica"),Expression.eq("name","Emma"));Expression.sql 作为补充,本方法提供了原生SQL语法的支持。我们可以通过这个方法直接通过SQL语句限定查询条件。下面的代码返回所有名称以“Erica”起始的记录:Expression.sql(“lower({alias}.name) like lower(?)”,"Erica%",Hibernate.STRING);其中的“{alias}”将由Hibernate在运行期使用当前关联的POJO别名替换。注意Expression 各方法中的属性名参数(如Express.eq中的第一个参数),这里所谓属性名是POJO中对应实际库表字段的属性名(大小写敏感),而非库表中的实际字段名称。Criteria,Query ,排序, 分页8.&& 局部属性的级连数据排序两种排序方式: 1.& Sort& 2. order-by, 前者通过JVM完成, 后者由数据库完成.&&& sort :可排序Set在Hibernate中对应为net.sf.hibernate.collection. SortedSet类, 实现了java.util.SortedSet .& 在set元素中可配置sort属性(sort=&#39;natural&#39;, 指定采用Java默认排序机制, 通过调用数据类型的compareTo方法. 可以自定义parator接口的实现, 来作为sort的属性值, 而实现自定义的排序算法. Map类型与Set基本一致, 但Bag和List不支持sort排序.&&& order-by:& 在元素中增加order-by属性(比如order-by="address desc" )可以实现数据库排序. 该特性利用了JDK1.4+ 中的LinkedHashSet以及LinkedHashMap, 由此必须在环境JDK1.4以上才可成功. Set, Map, Bag支持, List不支持该特性.9.&& Criteria/Query分页, Criteria排序限定返回的记录范围通过Criteria(或者Query)的setFirstResult, setMaxResults 方法可以限制一次查询返回的记录范围:Criteria criteria = session.createCriteria(TUser.class);//限定查询返回检索结果中,从第一百条结果开始的20条记录criteria.setFirstResult(99); //Base 0criteria.setMaxResults(20);对查询结果进行排序//查询所有groupId=2的记录& //并分别按照姓名(顺序)和groupId(逆序)排序Criteria criteria = session.createCriteria(TUser.class);criteria.add(Expression.eq("groupId",new Integer(2)));criteria.addOrder(Order.asc("name"));criteria.addOrder(Order.desc("groupId"));Criteria作为一种对象化的查询封装模式,不过由于Hibernate在实现过程中将精力更加集中在HQL查询语言上,因此Criteria的功能实现还没做到尽善尽美(这点上,OJB的Criteria 实现倒是值得借鉴),因此,在实际开发中,建议还是采用Hibernate 官方推荐的查询封装模式:HQL。&Hibernate Query Language (HQL)Criteria提供了更加符合面向对象编程模式的查询封装模式。不过,HQL(Hibernate Query Language)提供了更加强大的功能,在官方开发手册中,也将HQL作为推荐的查询模式。相对Criteria,HQL提供了更接近传统SQL语句的查询语法,也提供了更全面的特性。最简单的一个例子:String hql = "from org.hibernate.sample.TUser";Query query = session.createQuery(hql);List userList = query.list();上面的代码将取出TUser的所有对应记录。如果我们需要取出名为“Erica”的用户的记录,类似SQL,我们可以通过SQL 语句加以限定:String hql = "from org.hibernate.sample.TUser as user where user.name=&#39;Erica&#39;";Query query = session.createQuery(hql);List userList = query.list();其中我们新引入了两个子句“as”和“where”,as子句为类名创建了一个别名,而where子句指定了限定条件。HQL子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。关于HQL,Hibernate 官方开发手册中已经提供了极其详尽的说明和示例,详见本文HQL部分或者Hibernate官方开发手册。延迟加载(Lazy Loading)所谓延迟加载,就是在需要数据的时候,才真正执行数据加载操作, 避免性能浪费。Hibernate 2中的延迟加载实现主要针对:实体对象和集合(Collectio)。Hibernate 3同时提供了属性的延迟加载功能。hibernate2默认lazy= 而hibernate3默认为true.10. 实体对象的延迟加载在关于Session.get/load方法的描述中,我们曾经提到,通过load方法我们可以指定可以返回目标实体对象的代理。正常情况下,一个非延迟加载运行时,Hibernate已经从库表中取出了对应的记录,并构造了一个完整的TUser对象。通过class的lazy="true"属性, 使用了延迟加载机制之后, user对象属性均为null,此时并没有任何Hibernate并没有执行数据库查询操作。原因就在于Hibernate的代理机制。Hibernate中引入了CGLib作为代理机制实现的基础。CGLib可以在运行期动态生成Java Class。这里的代理机制,其基本实现原理就是通过由CGLib构造一个包含目标对象所有属性和方法的动态对象(相当于动态构造目标对象的一个子类)返回,并以之作为中介,为目标对象提供更多的特性。从上面的内存快照可以看到,真正的TUser对象位于代理类的属性中。当我们调用user.getName方法时,调用的实际上是代理类的getName( )方法, 它会首先检查CGLIB$CALLBACK_0.target中是否存在目标对象。如果存在,则调用目标对象的getName方法返回,如果目标对象为空,则发起数据库查询指令,读取记录、构建目标对象并将其投入"代理类的.target"。这样,用过一个中间代理,实现了数据延迟加载功能,只有当客户程序真正调用实体类的取值方法时,Hibernate才会执行数据库查询操作。11. 集合类型的延迟加载Hibernate延迟加载机制中,关于集合的延迟加载特性意义最为重大,也时实际应用中相当重要的一个环节。回到开篇提到的一个例子:如,之前示例中TUser对象在加载的时候,在非“延迟加载”的情况下,会同时读取其所关联的多个地址(adress)对象,对于确实需要对address进行操作的应用逻辑而言,关联数据的自动加载机制的确非常有效。但是,如果我们只是想要获得user的年龄(age)属性,而不关心user的地址(address)信息,那么自动加载address的特性就显得多余,并且造成了极大得性能浪费。为了获得user的性别属性,我们可能还要同时从数据库中读取数条无用的地址数据,这导致了大量无谓的系统开销。对于我们这里TUser对象的加载过程,如果要做到集合的延迟加载,也就意味着,加载TUser对象时只针对其本身的属性,而当我们需要获取TUser对象所关联的address信息时(如执行user.getAddresses时),才真正从数据库中加载address数据并返回。我们将前面一对多关系中的lazy属性修改为true,即指定了关联对象采用延迟加载:尝试执行以下代码:运行时抛出异常:如果我们稍做调整,将session.close放在代码末尾,则不会发生这样的问题。这意味着,只有我们实际加载user关联的address时,Hibernate才试图通过session从数据库中加载实际的数据集,而由于我们读取address之前已经关闭了session,所以出现了以上的错误。这里有个问题,如果我们采用了延迟加载机制,但希望在一些情况下,实现非延迟加载时的功能,也就是说,我们希望在Session关闭后,依然允许操作user的addresses属性。如,为了向View层提供数据,我们必须提供一个完整的User对象,包含其所关联的sddress信息,而这个User对象必须在Session关闭之后仍然可以使用。Hibernate.initialize方法可以强制Hibernate立即加载关联对象集:为了实现透明化的延迟加载机制,Hibernate进行了大量努力。其中包括JDK Collection接口的独立实现。如果我们尝试用HashSet强制转化Hibernate返回的Set型对象:就会在运行期得到一个java.lang.ClassCastException,实际上,此时返回的是一个Hibernate的特定Set实现“net.sf.hibernate.collection.Set”,而非传统意义上的JDK Set实现。这也正是我们为什么在编写POJO时,必须用JDK Collection Interface (如Set,Map),而非特定的JDK Collection实现类(如HashSet、HashMap)的原因(如private Set addresses;而非private HashSet addresses)。回到前面TUser类的定义:我们通过Set接口,声明了一个addresses属性,并创建了一个HashSet作为addresses的初始实例,以便我们创建TUser实例后,就可以为其添加关联的addrsee对象:此时,这里的addresses属性是一个HashSet对象,其中包含了一个address对象的引用。前面的 “脏数据检查”部分中,我们讨论过针对无关联实体的保存。那么,在现在的情况下,当前调用session.save(user)时,Hibernate如何处理其关联的Address对象集?通过Eclipse的Debug视图,我们可以看到session.save方法执行前后user对象发生的变化。可以看到,user对象在通过Hibernate处理之后已经发生了变化。首先,由于insert操作,Hibernate获得数据库产生的id值(在我们的例子中,采用native方式的主键生成机制),并填充到user对象的id属性。这个变化比较容易理解。另一方面,Hibernate使用了自己的Collection实现“net.sf. hibernate.collection.Set”对user中的HashSet型addresses属性进行了替换,并用数据对其进行填充,保证新的addresses与原有的adresses包含同样的实体元素。再来看下面的代码:根据之前的讨论我们知道,当代码执行到(1)处时,addresses数据集尚未读入,我们得到的addSet对象实际上只是一个未包含任何数据的net.sf.hibernate.collection.Set实例。代码运行至(2),真正的数据读取操作才开始执行。观察一下net..sf..hibernate.collection.Set.iterator方法我们可以看到:直到此时,真正的数据加载(read( )方法)才开始执行。Read方法将首先在缓存中查找是否有符合条件的数据索引。注意这里数据索引的概念,Hibernate在对集合类型进行缓存时,分两部分保存,首先是这个集合中所有实体的id列表(也就是所谓的数据索引,对于这里的例子,数据索引中包含了所有userid=1的adress对象的id清单),其次是各个实体对象。如果没有发现对应的数据索引,则执行一条Select SQL(对于本例就是select…fromt_address where user_id=?)获得所有符合条件的记录,接着构造实体对象和数据索引后返回。实体对象和数据索引也同时被分别纳入缓存。另一方面,如果发现了对应的数据索引,则从这个数据索引中取出所有id列表,并根据id列表依次从缓存中查询对应的数据,则执行相应的Select SQL获得对应的address记录(对于本例就是select…from t_adress wahere id+?)。这里引出了另外一个性能关注点,即关联对象的缓存策略。如果我们为某个集合类设定了缓存,如:注意这里的只会使得Hibernate对数据索引进行缓存,也就是说,这里的配置实际上只是缓存了集合中的数据索引,而并不包括这个集合中的各个实体元素。执行下面的代码:观察屏幕日志输出:看到,第二次获取关联的addresses集合的时候,执行了3次Select SQL。正是由于…的设定,第一次addresses集合被加载之后,数据索引已经被放入缓存。第二次再加载addresses集合的时候,Hibernate再缓存中发现了这个数据索引,于是从索引里面取出当前所有的id(此时数据库中有3条符合的记录,所以共获得3个id),r然后依次根据这3个id在缓存中查找对应的实体对象,但是没有找到,于是发起了数据库查询,由Select SQL根据id从t_address表中读取记录。我们看到,由于缓存中数据索引的存在,似乎SQL执行的次数更多了,这导致第二次借助缓存的数据查询比第一次性能开销更大。导致这个问题出现的原因何在?这是由于我们至为集合类型配置了缓存,这样Hibernate只会缓存数据索引,而不会将集合中的实体元素同时也纳入缓存。我们必须为集合类型中的实体对象也指定缓存策略,如:此时,Hibernate才会对集合中的实体也进行缓存。再次运行之前的代码,得到以下日志输出:可以看到,第二次查询没有执行任何SQL即宣告完成,所有的数据都来自缓存,这无意对性能的提升有着及其重要的意义。上面我们探讨了 net.sf. hibernate.collection.Set.iterate方法,同样,观察 net.sf.hibernate.collection.Set.size/isEmpty方法或者其他hibernate collection中的同类型方法实现,我们可以看到同样的处理方式。通过自定义Collection类型实现数据延迟加载的原理也就再于此。这样,通过自定义Collection实现,Hibernate就可以在Collection层从容的实现延迟加载特性。只有程序真正读取这个Collection的内容时,才激发底层数据库操作,这为系统的性能提供了更加灵活的调整手段。12. 属性的延迟加载在前面的内容中,我们讨论了关于实体,及其关联集合对象的延迟加载机制。这些机制为改进持久层性能提供了一个重要渠道。根据我们已有的经验来看,上面这两种延迟加载模式,实质上都是面向数据实体。我们可以决定是否即刻加载某个实体,或者某个实体集合。如果需要对实体的某个部分(如某个属性)应用延迟加载策略,我们应如何入手?在基础篇中,我们曾经探讨了有关实体粒度设计的主题。通过对同一库表建立不同粒度的实体映射关系,我们可以变通的实现库表的部分加载,不过,这并非我们这里所说的延迟加载,另一方面,这样需要付出大量的额外工作。另外,我们也可以在HQL中通过Select子句限定加载的属性列表。不过,随之而来HQL语句的琐碎语法实在令人厌倦。在Hibernate 2中,为了避免实体加载可能带来的性能浪费,我们只能采取以上两种策略。Hibernate团队显然也意识到了这个问题, Hibernate3中通过property节点的lazy属性可以为特定属性指定延迟加载.但还需要借助类增强器对二进制class文件进行强化处理.(buildtime bytecode instrumentation).数据保存13. Session.save方法接受一个实体对象,执行时:&&& 在Session内部缓存中寻找对象, 如果数据已经保存(Persistent状态), 则直接返回.即使状态已经变化, 也将在脏数据检查中判定, 并执行相应update操作.&&& 如果实体类实现了lifecyle接口, 则调用待保存对象的onSave方法.&&& 如果实体类实现了Validatable接口, 则调用其validate()方法.&&& 如果有, 调用拦截器(Interceptor)的onSave方法.&&& 构造Insert SQL并执行. 可能会设置对象的id值.&&& 将对象放入内部缓存. (不纳入二级缓存, 因为Hibernate认为在事务的剩余部分被修改的几率很高).&&& 如果存在级连关系, 则递归处理.14. Session.update方法可以把对象从Detached状态转换为Persisitent状态.&&& 根据实体对象的id在Session缓存中查找, 如果发现, 则认为对象已经处于Persistent状态, 直接返回.(说明Persistent状态的数据调用update不起作用.)&&& 初始化对象的状态信息, 并纳入缓存.& 本身并不发送Update SQL完成更新操作, 但是Session.flush方法将执行Update SQL.(mit在提交数据库事务之前调用了Session.flush)15. Session.saveOrUpdate方法执行步骤:&&& 在Session缓存中查找, 找到就直接返回.&&& 如果有, 执行实体类的Interceptor.isUnsave(), 判断对象是否为未保存.&&& 未保存(Transient), 则调用save方法保存.&&& 如果已经保存(Detached), 则调用update时对象与Session关联.数据批量操作16. 数据批量操作--保存保存的数据将纳入缓存.由于二级缓存可以配置最大容量, 但内部缓存却没有容量限制, 所以批量操作中, 应该考虑到控制内部缓存的过度增长而出现OutOfMemeoryError错误.可以在数据保存过程中周期性的对Session调用flush和clear方法, 确保Session的容量不至于太大.也可以设置hibernate.jdbc.batch_size参数, 指到批量操作中每次提交SQL的数量. (MySql Driver不支持BatchUpdate).17. 数据批量操作--删除--hibernate2轻量级的ORM都面临一个问题, 数据库的改变需要在缓存中同步. 所以表面上的一个HQL删除, 往往执行的是1+N次操作. 第一次是查询, 第二次是逐条删除.由此的问题:&&& 内存消耗.如果数据量过大, find方法很容易导致OutOfMemeoryError错误. 可以考虑使用iterate方法逐条获取数据在执行删除. Hibernate2.16以后的版本, 提供了基于游标的数据遍历操作(前提是JDBC驱动必须支持游标), 通过游标, 我们可以逐条获取数据, 使得内存比较稳定. Query的scroll方法得到ScrollableResults.&&& 执行效率. 同样可以调整hibernate.jdbc.batch_size参数.18. 数据批量操作--删除--hibernate3引入了bulk delete/update操作, 通过一条独立的SQL完成对数据的批量删除/更新. 方法是, 使用hsql创建Query, 再调用Query的executeUpdate()方法.但是无法解决缓存同步问题(包括一级缓存和二级缓存):
孔孝真,日出生于首尔,韩国女演员。早期以模特儿出道,拍摄杂志目录、电视广告。
徐立,青年女演员,人气歌手。毕业于中央戏剧学院表演系。大学期间组建乐团“爱乐团”担任主唱,一首《天涯》红遍大江南北,徐立}

我要回帖

更多关于 持久化对象状态 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信