Hibernate 操纵对象 Session用法

来源:互联网 发布:人工智能硬件 编辑:程序博客网 时间:2024/04/30 07:37

          Session接口是Hibernate向程序提供操纵数据库的最主要接口,它提供了基本的保存、更新、删除和查询方法。它有一个缓存,保存了持久化对象,当清理缓存时,按照这些持久化对象同步更新数据库


JAVA对象在JVM中的生命周期
就用new语句创建一个对象是,JAVA虚拟机会为这个对象分配内存空间,只要这个对象不被任何引用变量引用,它就结束生命周期.如:
//创建一个Customer对象和两个Order对象,定义三个引用变量c、o1、o2Customer c=new Customer(“Tom”,new HashSet());Order o1=new Order(“Tom_ 001”,null);Order o2=new Order(“Tom_002”,null)//建立关联关系o1.setCustomer(c);c.getOrders().add(o1);//c、o1、o2置null,不再引用对象,o1=null;//第一个Order不被o1引用,但它被Customer引用o2=null;//这个对象(Order o2=new Order(“Tom_002”,null))结束生命c=null;//因为关联第一个Order到现在才结束生命

理解Session的缓存
缓存是一个内存空间,这个空间放一些JAVA集合,这些集合就是Session的缓存,如:
private final Map entitiesByKey;
entitiesByKey.put(key,object);//向Session的缓存加入一个持久化对象
entitiesByKey.romove(key);//从Session缓存删除一个持久化对象

对象被加入缓存中,即使不被程序的变量引用,只要缓存不被清空,或被清空,但程序中有变量引用该对象,对象仍然存在,在以后的检索中,是先从缓存检索,没有才去数据库中检索.如:
Customer c1=new Customer(“Tom”,new HashSet());session.save(c1);//持久化对象,加入到缓存Long id=c1.getId();c1=null;//不引用对象了,但对象仍存在缓存Customer c2=(Customer)session.load(Customer.class,id);//从缓存中读取对象tx.commit();session.close();//关闭,清空缓存System.out.println(c2.getName());//清空缓存,但对象还被引用,仍然在生命周期内c2=null;//对象生命结束
Session缓存的作用:
1.       可以从缓存中读取数据,减少访问数据库的频率,提高性能
2.       保证缓存中对象和数据库的相关记录一致.当缓存中对象数据改变了,Session能够把几条相关的SQL语句合并为一条执行,减少访问数据库的次数
3.       当缓存中持久化对象之间存在循环关联关系时,Session保证不出现访问对象图的死循环
Session在清理缓存时,才执行SQL语句
Session会在下面的时间点清理缓存
1.         调用net.sf.hibernate.Transaction.commit()方法,先清理缓存,然后提交事务
2.         调用Session的find()或者iterate()时,如果持久化对象属性有变化就清理缓存
3.         显式调用Session的flush()

flush()和commit()方法的区别:flush()不会提交事务,commit()先调用flush() 方法,后提交事务,使更新被永久保存下来


Session的setFlushMode()方法用来设定清理缓存的时间点,方法如:
session.setFlushMode(FlushMode.COMMIT);

有三种清理模式:

清理缓存模式

Session的查询方法

Sessioncommit()

Sessionflush()

FlushMode.AUTO

清理

清理

清理

*.COMMIT

不清理

清理

清理

*.NEVER

不清理

不清理

清理



其中*.AUTO为默认值.如果能肯定清理和不清理查询的结果一样,用*.COMMIT来提高性能.


什么时候用flush()方法?
1.         插入、删除、更新某个持久化对象时会引发数据库中的触发器,使用flush()方法让它马上执行语句,触发触发器

2.         JDBC驱动程序不健壮,导致Hibernate自动清理无法正常工作


在Hibernate应用中JAVA对象的状态
对于需要被持久化的对象,在它生命周期中,有三个状态
1.         临时状态:刚刚用new语句创建,还没有被持久化,这不在Session的缓存中
2.         持久化状态:已经被持久化,在Sesson缓存中
3.         游离状态:已经被持久化,但不在Session缓存中

对象状态转换图:

孙卫琴《精通Hibernate...》7操纵持久化对象


临时对象的特征
1.不在Session的缓存中,不与任何Session实例关联
持久化对象的特征
1.  在Session的缓存中,总被一个Session实例关联,Session被清理时,会根据持久化对象属性的变化来同步更新数据库,当一个持久化对象关联一个临时对象,在允许级联保存的情况下,Session在清理缓存时把这个临时对象也转变为持久化对象.一个Session实例对应一个缓存,在同一个缓存中数据库表的记录只对应(只有)一个持久化对象.同一个持久化对象可以被多个Session实例关联(共用),如:
Session session1=sessionFactory.openSession();Session session2=sessionFactory.openSession();Transaction tx1=session1.beginTransaction();Transaction tx1=session1.beginTransaction();Customer c=(Customer)session1.load(Customer.class,new Long(1));session2.update(c);//Customer对象被加入到session2缓存,c.setName(“Jack”);tx1.commit();//执行update语句tx2.commit();//执行同样的update语句,因为共用一个持久化对象session1.close();//应避免一个对象同时被多个Session实例关联session2.close();
游离对象的特征

不在位于缓存中,不被Sesion关联


Session的保存、更新、删除和查询方法

Session的save()方法
Customer customer =new Customer();customer.setName(“Tom”);Session session=sessionFactory.openSession();Transaction tx=session.beginTransaction();session.save(customer);//对象加入缓存中,变成持久化对象, 然后根据生成器分配OID//如果要程序为对象指定OID,调用如:save(customer,new Long(9))重载方法customer.setName(“Jack”); //修改属性tx.commit();//清理缓存才执行一条insert语句和一条update语句session.close();

Session的update()方法 .使用方法如:
Customer customer =new Customer();customer.setName(“Tom”);Session session1=sessionFactory.openSession();Transaction tx1=session.beginTransaction();session.save(customer);//对象加入缓存中,变成持久化对象, 然后根据生成器分配OIDtx.commit();//清理缓存才执行一条insert语句session.close();//customer对象变为游离状态 Session session2=sessionFactory.openSession();Transaction tx2=session.beginTransaction();customer.setName(“Jack”); //修改属性session2.update(customer);//游离状态变为持久化状态customer.setName(“Linda”); //又修改属性 tx2.commit();//清理缓存,只执行一条update语句(多条update变成一条来执行)session2.close();

注意:
(1)如果希望Session在Customer对象属性有所改变,才执行update,可以把映射文件<class>元素的select-befor-update设为true,让在执行update前先执行select,查看属性是否有变化,有变化才执行update

(2)update()关联一个游离对象时,如果缓存存在相同OID的同类的持久化对象,会抛出异常;或者数据库不存在相应的记录,也会抛出异常


Session的saveOrUpdate()方法
saveOrUpdate()方法包含save()和update()功能,如果传入的参数是临时对象(没有保存过)就调用save()方法;如果传入的参数是游离对象,就调用update()方法(因为已经保存过了);如果是持久化对象,就直接返回(清理缓存时会同步更新数据库).如果满足以下情况之一,Hibernate把它作为临时对象
1.       JAVA对象的OID为null
2.       映射文件中<id>元素的unsaved-value(未保存过的值)属性值和OID一致
3.       JAVA对象具有version属性并且值为null
4.       在映射文件中为version属性设置了unsaved-value属性,并且version属性值和unsaved-value属性值一致
如果JAVA对象的id属性为java.lang.Long类型,默认为null,故new出来的对象一定是临时对象;如果为long类型,默认为0,这就要显式设置<id>元素的unsaved-value属性,它默认为null;
<id name=”id” column=”ID” unsaved-value=”0”>
       <generator class=”increment”/>

</id>


Session的load()和get()方法

load()和get()方法都能根据给定的OID从数据库中加载一个持久化对象,它们的区别在于:当数据库不存在与OID对应的记录时,load()方法抛出异常,而get()方法返回null

Session的merge()方法

merge()方法能够把一个游离的对象的属性复制到一个持久化对象中。当Session用update()方法关联一个游离对象时,如果Session缓存中已经存在一个同类型并且OID相同的持久化对象,那么update()方法会抛出NonUniqueException

      //创建UserInfo实例           UserInfo userInfo = new UserInfo(); //使之成为游离状态           userInfo.setId(11112);           userInfo.setName("RW3");           userInfo.setSex("M");           //创建UserInfo实例           UserInfo userInfo2 = new UserInfo(); //使之成为游离状态           userInfo2.setId(11112);           userInfo2.setName("RW4");           userInfo2.setSex("F");           //启动Session           Session session = HibernateSessionFactory.currentSession();           //启动事务           Transaction tx = session.beginTransaction();           //调用merge方法,此时UserInfo实体状态并没有被持久化           session.merge(userInfo);           //调用merge方法,此时UserInfo实体状态并没有被持久化           //但是数据库中的记录被更新了           ①session.merge(userInfo2);           //merge方法与update方法的差别在于针对同样的操作update方法会报错           //原因在于update方法使得实体状态成为了持久化状态,而Session中不允许两个持久化实体有同样的持久化标识           ②//session.update(userInfo);           //session.update(userInfo2);          //以下两句不会发送SQL,因为userInfo2不是持久化状态的实体          ③userInfo2.setName("RW5");           userInfo2.setSex("M");           //提交事务           tx.commit();           //关闭Hibernate Session           HibernateSessionFactory.closeSession(); 

 Session的delete()方法
delete()方法用于从数据库中删除与JAVA对象对应的记录.如果传入的参数是持久化对象,在清理缓存时会执行delete语句,当调用close()方法时,再从缓存中删除对象;如果传入的是游离对象,它先变成持久化对象,再操作.如果是希望删除多个对象,可以使用另一种重载形式的delete()方法,如:
session.delete(“form Customer as c where c.id>8”);
级联操纵对象
实际应用,对象与对象之间相互关联.因此缓存中存放的是一幅相互关联的对象图.例如以下代码看似


只加载了一个Category(种类)对象:
Category appleCategory=(Category)session.load(Category.class,new Long(2));
实际上,Session加载了所有和appleCategrory直接关联或间接关联的Category对象,见图:

孙卫琴《精通Hibernate...》7操纵持久化对象


 
这样就可以通过getParentCategory()方法导航到父类的Categroy对象,通过getChildCategories().iterator().next()导航到子类别的Category对象(也可以说是把因主外键关联与形成的图的对象都加载,它的一条记录相当于用多表连接查询结果一样).那么如何操纵与当前对象关联的其他对象?

在映射文件中,在<set>、<many-to-one>和<one-to-one>等元素中设置cascade(层叠)属性。
cascade描述如下:

cascade属性值

描述

none(决不)

在保存、更新或删除当前对象时,忽略其他关联对象。这是默认值

save-update

使用save(),update()saveOrUpdate()方法时,级联保存或更新对象

delete

使用delete()方法时,级联删除所有的关联对象

all

使用save(),update(),saveOrUpdate(),evict(),lock()delete(),级联...

delete-orphan

删除所有和当前对象解除关联的对象

all-delete-orphan

包含alldelete-orphan的行为.



例子:
<set name=”childCategories” cascade=”save-update” inverse=”true”>
       <key column=”CATEGORY_ID”/>
       <one-to-many class=”mypack.Category”/>
</set>

保存或更新当前Category对象时,会调用getChildCategories()方法,导航到所有子类别Category对象,然后级联保存或更新

1 级联保存临时对象Category foodCategory=new Category(“food”,null,new HashSet());Category fruitCategory=new Category(“fruit”,null,new HashSet());Category appleCategory=new Category(“apple”,null,new HashSet());//建立关联foodCategory.addchildCategory(fruitCategory);fruitCategory.addchildCategory(appleCategory);saveOrUpdate(foodCategory);//级联保存三个临时对象,2 更新持久化对象tx=session.beginTransaction();Category fruitCategory=findCategoryByName(session,”fruit”);//得到持久化对象Category orangeCategory=new Category(“orange”,null,new HashSet());fruitCategory.addchildCategory(orangeCategory);//关联临时对象tx.commit();//更新持久化对象,持久化orangeCategory对象,不是级联3 持久化临时对象Category foodCatygory=findCategoryByName(“food”);//不同Session缓存,foodCategory对//于这个Session缓存是一个游离对象Category vegetableCategory=new Category(“vegetable”,null,new HashSet());//临时对象foodCategory.addChildCategory(vegetableCategory);//关联对象saveOrUpdate(vegetableCategory);//持久化vegetableCategory,会级联更新foodCategor、fruitCategory对象(遍历关联图中所有对象,并更新它们).如果有1000个Category对象,Session就会多执行1000条update语句(这些update语句执不执行数据库的数据不变,因为它们没有数据变化),解方法是把<many-to-one>元素的cascade属性设为”none”,就只更新子类,不更新父类和与父类关联的其它对象4 更新游离对象//得到游离对象,因为不同Session缓存不同,不在我这个缓存而又不用new就是游离对象Category vegetableCategory=findCategoryByName(“vegetable”);vegetableCategory.setName(“green vegetable”);Category tomatoCategory=new Category(“tomato”,null,new HashSet());vegetableCategory.addChildCategory(tomatoCategory);//关联对象saveOrUpdate(vegetableCategory);//因为<set>和<many-to-one>元素的cascade属性都为”save-update’会级联更新vegetableCategory的子类和父类,使执行多余的update语句,解决方法是把<many-to-one>的cascade 属性设为”none”只更新自已的子类


遍历对象图
以下章的最终图为:
孙卫琴《精通Hibernate...》7操纵持久化对象

是一个递归算法,用来遍历以上的图略

 
原创粉丝点击