1. 缓存
缓存(Cache): 介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写硬盘(永久性数据存储源)的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝,缓存的物理介质通常是内存。
2. 二级缓存
Hibernate 提供缓存机制:一级缓存、二级缓存
一级缓存:线程级别的,session级别缓存,在一次请求中共享数据。
二级缓存:进程级别的,sessionFactory级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存。SessionFactory的缓存两部分:内置缓存:使用一个Map,用于存放配置信息,预定义HQL语句等,提供给Hibernate框架自己使用,对外只读的,不能操作。外置缓存:使用另一个Map,用于存放用户自定义数据。默认不开启。外置缓存hibernate只提供规范(接口),需要第三方实现类。外置缓存又成为二级缓存。
3.二级缓存构成
二级缓存有四部分构成,分别是其一是类级别缓存,其二是集合级别缓存,其三是查询缓存,其四是时间戳。
4.并发策略
并发策略有四种,分别是transactional ,read-write,nonstrict-read-write ,read-only;
一般选用read-write,read-only
5.应用场景
适合使用二级缓存的:
1>很少被修改;
2>不是很重要的数据,允许出现偶尔并发问题。
不适合使用二级缓存的:
1>经常被修改;
2>财务数据,绝对不能出现并发问题;
3>与其他应用程序共享的数据
6. 应用实例
1>类级别缓存
@Test
public void fun1(){
Session session = HibernateUtils.OpenSession();
session.beginTransaction();
//------------------------------
Customer c1 = (Customer)session.get(Customer.class,1);
session.clear();//关闭一级缓存
Customer c2 = (Customer)session.get(Customer.class,1);
System.out.println(c1 == c2);
//------------------------------
session.getTransaction().commit();
session.close();
}
结果:false
分析:console端打印一条SQL 语句 = >二级cache存在, false => 二级缓存不是对象
类级别缓存存储的数据对象的散列信息,使用时在一级缓存中组装成对象。
2>集合级别缓存
public void fun1(){
Session session = HibernateUtils.OpenSession();
session.beginTransaction();
//------------------------------
Customer c1 = (Customer)session.get(Customer.class,1);
for(Order o : c1.getOrders()){
System.out.println(o.getName());
}
session.clear();
Customer c2 = (Customer)session.get(Customer.class,1);
Iterator<Order> it = c2.getOrders().iterator();
while (it.hasNext()){
Order o = it.next();
System.out.println(o.getName());
}
//------------------------------
session.getTransaction().commit();
session.close();
}
结果:运行到c2, 通过查询order 的id 查询order
分析:集合级别缓存存储的是customer 的id ,以及customer下 order的id 信息。
3>查询缓存
//查询缓存
// 注意:对HQL查询
@Test
public void fun1(){
Session session = HibernateUtils.OpenSession();
session.beginTransaction();
//------------------------------
Query query = session.createQuery("from Customer");
//使用二级查询缓存
query.setCacheable(true);
//查询时,优先从二级缓存中查找,若没有就执行语句,将结果放入二级缓存中
List<Customer> list = query.list();
session.clear();
//使用二级查询缓存
query2.setCacheable(true);
//查询时,优先从二级缓存中查找,若没有就执行语句,将结果放入二级缓存中
List<Customer> list2 = query2.list();
//------------------------------
session.getTransaction().commit();
session.close();
}
结果:query2 没有打印sql语句
分析:查询缓存中存取的不是HQL语句,而是HQL对应生成的sql语句
4> 时间戳缓存
//timestamp
// 注意:对HQL查询
@Test
public void fun1(){
Session session = HibernateUtils.OpenSession();
session.beginTransaction();
//------------------------------
Customer c1 = (Customer) session.get(Customer.class,1);
System.out.println(c1.getName());
session.createQuery("update Customer set name=:name where id=:id")
.setString("name","jack").setInteger("id",1).executeUpdate();
session.clear();
Customer c2 = (Customer) session.get(Customer.class,1);
System.out.println(c2.getName());
//------------------------------
session.getTransaction().commit();
session.close();
}
结果:jack
分析:c1 数据存到缓存中,此时time1,但是后面执行了跟新数据库的操作,此时time2,再次查询时,会对比两个时间,time2 较新,所以c2会重新查看数据库,并且更新缓存。时间戳是保证存储在缓存区的数据是有效的。