Hibernate持久化对象状态

持久化对象 PO =  POJO + xml映射 

1、 hibernate 将持久化对象分为三种状态

         transient(瞬时态、临时态) : 没有持久化标识 OID 、未与Session关联

         persistent(持久态):存在持久化标识OID 、与Session关联(在事务提交 和 Session关闭之前)

         detached  (脱管态、离线态) : 存在持久化标识OID ,未与Session关联

Hibernate持久化对象状态_第1张图片

2 、持久化对象三种状态转换

Hibernate持久化对象状态_第2张图片

         1) 瞬时态对象:  new Book() 获得

                   瞬时 -- 持久  save()  saveOrUpdate()

                   瞬时 -- 脱管  book.setId(1) ; 为瞬时对象设置OID

         2) 持久态对象:  get() / load()  、 Query、 Criteria  从数据库查询

                   持久 -- 瞬时  delete()

                   持久 -- 脱管  close() 、evict() 、clear()

         3) 脱管态对象  无法直接获得

                   脱管 -- 瞬时  book.setId(null); 移除对象OID

                   脱管 -- 持久  update() 、saveOrUpdate() 、 lock() 过时

3 Session缓存(一级缓存)      

Hibernate框架中提供两级缓存 SessionFactory级别的缓存、Session级别的缓存

         SessionFactory 级别的缓存 ---- 二级缓存 (外置,需要引入第三方插件)

         Session 级别缓存 ----- 一级缓存 (内置,直接使用 )

l  在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期

l  当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图get()、 load()对象时,会判断缓存中是否存在该对象,有则返回,此时不查询数据库。没有再查询数据库

l  Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷出缓存(flush)

默认情况下 Session 在以下时间点刷出缓存

a           当应用程序调用 Transaction commit()方法的时, 该方法先刷出缓存(session.flush()),    然后在向数据库提交事务(tx.commit())

b           当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先         刷出缓存,以保证查询结果能够反映持久化对象的最新状态

c           调用 Session 的 flush() 方法

hibernate快照

         当session加载了customer对象后,会为customer对象的值类型的属性复制一份快照。当刷出缓存时,     通过比较对象的当前属性和快照,来判断对象的哪些属性发生了变化

案例: 编程证明一级缓存是存在的

                   Session session =HibernateUtils.openSession();

                   Transaction transaction =session.beginTransaction();

                   // 所有持久态对象 都会被放入一级缓存

                   Book book = (Book)session.get(Book.class, 1); // 持久态 放入缓存

                   System.out.println(book);

                   // 再次执行查询 --- 直接使用一级缓存中数据(控制台上的查询语句仍是只有一句)

                   Book book2 = (Book)session.get(Book.class, 1);

                   System.out.println(book2);

                   transaction.commit();

                   session.close();

案例 : 快照和缓存存储原理 ,测试快照自动 flush数据

                   Session session =HibernateUtils.openSession();

                   Transaction transaction =session.beginTransaction();

                   // 先将图书查询出

                   Book book = (Book)session.get(Book.class, 1);// 持久态

                   book.setPrice(200d); // 修改一级缓存对象数据

                   // 不调用update ,是否可以更新(有transaction.commit()就有flush操作,就能更新)

                   transaction.commit(); // 如果 不flush ,数据不会改变

                   session.close();

 

一级缓存常见操作  flush 、evict 、clear 、refresh

         * flush 比较缓存数据和快照数据是否一致,如果改变,将缓存数据更新到数据库(快照也更新,不会      清除缓存数据)

         * clear 会清除所有一级缓存数据(所有持久对象都会变为脱管对象)

         * evict 清除指定对象的一级缓存数据(被清除的对象,由持久变为脱管)

         * refresh  使用数据库中数据去覆盖缓存和快照的数据

 

一级缓存的flush 模式  FlushMode

Hibernate持久化对象状态_第3张图片

         * 通过session.setFlushMode 设置一级缓存刷出时间点

         * 默认FlushModel.AUTO  在 Transaction.commit  Query查询  session.flush  执行数据flush

         刷出session.flush > Transaction.commit > Query 查询

         * COMMIT  会在 session.flush和 Transaction、commit

         * MANUAL  只会在session.flush时 执行数据flush

         如果 使用MANUAL 必须 调用session.flush 才会将缓存数据更新到数据库,transaction的commit 不        会flush数据

ALWAYS和AUTO的区别

         当hibernate缓存中的对象被改动之后,会被标记为脏数据(即与数据库不同步了)。当 session设置为         FlushMode.AUTO时,hibernate在进行查询的时候会判断缓存中的数据是否为脏数据,是则刷数据库,     不是则不刷,而always是直接刷新,不进行任何判断。很显然auto比always要高效得多

 

4、 持久化对象的操作

         1) save 方法  瞬时态对象 转换 持久态对象

         如果采用数据库主键自增策略,执行save方法时,第一时间将insert语句发送到数据库,获得生成id ,  保存瞬时对象中,成为持久对象。持久化对象 OID 不能随意修改

         2) update 方法 将脱管变为持久

          将数据更新到数据库, 放入一级缓存

          如果脱管数据和数据库是一样的,执行update就没有意义,但是update任然会执行。如果设置select-before-update 属性,就会在修改之前先查询

* select-before-update="true">

          如果更新脱管对象OID 在数据库不存在,就会发生如下异常 

          * org.hibernate.StaleObjectStateException: Row was updated or deleted byanother transaction (or unsaved-value mapping was incorrect):[cn.itcast.domain.Book#3]

          如果 更新脱管对象时,一级缓存中已经存在相同OID的持久对象, 会发生异常

          * org.hibernate.NonUniqueObjectException: a different object with thesame identifier value was already associated with the session:[cn.itcast.domain.Book#2]

         3) saveOrUpdate

                   如果操作目标对象,没有OID (OIDnull OID为设置unsaved-value),执行save

                   如果操作目标对象,存在OID ,执行update

         例:在Book.hbm.xml设置 如果操作Book OID1000,框架会认为Book对象是一个瞬时对象       

    4) get 、load

         get 立即执行SQL语句,返回目标对象

         load 默认采用延迟加载机制,返回目标类子类对象 (代理对象),不会立即执行SQL语句,会在访问对象内除了id之外属性时执行SQL

         如果OID在目标数据库不存在,get立即执行返回 nullload 返回代理对象,访问对象的值时,抛出异常 ObjectNotFoundException

         5) delete 删除

         可以删除一个脱管对象或者一个持久对象的,对于单表操作删除脱管对象和持久对象无区别,对于多表操作有外键处理区别

                   * 原理:先将脱管对象转换为持久对象再删除

                                                        注:被删除对象不要再使用  

你可能感兴趣的:(个人javaweb学习笔记)