时间:2017-1-20 14:48
——一级缓存
1、什么是缓存
缓存是将数据库、硬盘上的文件中的数据,放入到缓存中。
缓存就是内存中的一块空间,当再次使用数据时,可以直接从内存中获得。
2、缓存的优点
提高程序运行的效率,缓存技术是Hibernate的一个优化手段。
3、Hibernate分为两个级别的缓存:
1)一级缓存:
Session级别的缓存,一级缓存与Session生命周期一致,是自带的,不可卸载。
一级缓存缓存的是对象的引用。
2)二级缓存:
SessionFactory级别的缓存,不是自带的,如果想要使用,则必须配置。
4、理解Session缓存(一级缓存)
1)在Session接口的实现中包含了一系列的Java集合,这些Java集合构成了Session缓存,只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。
2)当Session的save()方法持久化一个对象时,该对象被载入一级缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中,当视图get()、load()获取对象时,会判断缓存中是否存在该对象,有则返回,此时不再查询数据库,没有再查询数据库。
3)Session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步更新数据库,这一过程被成为刷出缓存(flush)
4)默认情况下,Session在以下时间点刷出缓存:
* 当应用程序调用Transaction的commit()方法时,该方法先刷出缓存(session.flush()),然后再向数据库提交事务。
* 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先刷出缓存,以保证查询结果能够反应持久化对象的最新状态。
* 调用session的flush()方法。
——证明Hibernate一级缓存的存在
示例代码:
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// save()方法可以向一级缓存中存放数据
Book book = new Book();
book.setName("Hibernate");
book.setAuthor("张三");
book.setPrice(50D);
Integer id = (Integer)session.save(book);
// 第一次查询会发送SQL语句
Book book1 = (Book)session.get(Book.class, 1);
System.out.println(book1);
// 第二次查询不会发送SQL语句,并且获取到的对象地址也是相同的,因为第一次查询已经将对象放入缓存了
Book book2 = (Book)session.get(Book.class, 1);
System.out.println(book2);
tx.commit();
session.close();
}
——Hibernate快照区
当session加载了customer对象后,会为customer对象的值类型的属性复制一份快照。
当刷出缓存时,通过比较对象的当前属性和快照,来判断对象的哪些属性发生了变化,如果对象的属性和快照区一致,则不执行update操作。
自动更新数据库是依赖了快照区。
快照的存才提高了Hibernate的执行效率。
可以通过断点进行查看。
示例代码:
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 获得一个持久态对象
Book book = (Book)session.load(Book.class, 2);
book.setName("Hibernate");
/*
* 当修改对象和数据库中数据一致时,不会提交更新语句
* 通过快照区来判断数据是否一致
*/
tx.commit();
session.close();
}
——一级缓存的管理
一级缓存与Session的生命周期相关,Session的生命周期结束,一级缓存也就销毁了。
Session中的方法:
* flush()
将缓存中的数据刷出到数据库。
* clear()
清空缓存中所有数据。
* evict()
清空指定对象一级缓存数据,使对象变为离线态。
* refresh()
使用快照区将一级缓存中的数据覆盖,使一级缓存中的数据变为从数据库查询时的初始状态。
示例代码:
// 一级缓存的管理:clear() / evict()
public void fun5(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Book book1 = (Book) session.get(Book.class, 1);
Book book2 = (Book) session.get(Book.class, 2);
System.out.println(book1);
System.out.println(book2);
// session.clear(); // 清空一级缓存区域
session.evict(book1); // 清空一级缓存中的指定对象
Book book3 = (Book) session.get(Book.class, 1);
Book book4 = (Book) session.get(Book.class, 2);
System.out.println(book3);
System.out.println(book4);
tx.commit();
session.close();
}
——一级缓存的刷出时机
FlushMode类:
常量:
* ALWAYS
普通查询、手动flush()、事务提交都会刷新。
* AUTO(默认值)
有些查询会刷出缓存,手动调用flush()、事务提交会刷出。
* COMMIT
只有在事务提交时、手动调用flush()会刷出。
* MANUAL
只有在flush()时刷出。
* NEVER
已过时,用MANUAL替代。
严格程度:MANUAL > COMMIT > AUTO > ALWAYS
通过session.setFlushMode(FlushMode.AUTO)进行设置,一般不会修改其值。
——操作持久化对象的方法
1、save()
1)session的save()方法使一个瞬时对象转变为持久态对象
2)session的save()方法完成以下操作:
* 把瞬时对象加入到Session缓存中,使它进入持久化状态。
* 选用映射文件指定的标识符生成器,为持久化对象分配唯一的OID,在使用代理主键的情况下,setId()方法为瞬时对象设置OID是无效的。
* 计划执行一条insert语句,把Customer对象当前的属性值组装到insert语句中。
3)Hibernate通过持久化对象的OID来维持它和数据库相关记录的对应关系,当Customer对象处于持久化状态时,不允许程序随意修改它的ID。
2、update()
1)session的update()方法使一个脱管对象转变为持久化对象,并且计划执行一条update语句。
2)在<class>标签上设置select-brefore-update="true",会在更新之前先查询,如果数据存在并且与待更新数据一致,则不执行更新。
3、saveOrUpdate()
1)根据对象的不同状态执行save()或update()方法。
* 如果一个对象是瞬时态对象:执行save()方法
* 如果对象是一个脱管态对象:执行update()方法
如果在执行update()时设置的id不存在,会报错,可以在<id>标签上设置一个unsaved-value="-1",这样如果设置的id是-1,则会继续自动生成主键并save()
4、delete()
将持久态对象转换为瞬时态对象。
5、get() / load()
获得一个持久态对象。
——总结
1、Hibernate中两个基本缓存
* 一级缓存:与Session生命周期一致
* 二级缓存:与SessionFactory生命周期一致
2、证明一级缓存的存在
3、一级缓存的结构 - 快照区
* 用来自动完成数据库更新操作
4、Hibernate一级缓存的管理
* clear()
* evict()
* flush()
* refresh()
5、一级缓存刷出时机
* ALWAYS
* AUTO:默认值
* COMMIT:事务提交/flush()时刷出
* MANUAL:手动flush()时刷出
6、操作持久化对象常用方法
* save()
* update()
* saveOrUpdate()
* delete()
* get() / load()