什么是缓存?它就是内存中的临时数据。
为什么使用缓存?减少和数据库交互的次数,从而提高查询效率。
适用缓存的数据:经常查询的,并且不经常修改的,同时数据一旦出现问题,对最终结果影响不大的。
不适用缓存的数据:
不管是否经常查询,只要经常修改的,都可以不用缓存;
并且如果数据由于使用缓存,产生了异常数据,对最终结果影响很大,则不能使用;
例如:股市的牌价、银行的汇率、商品的库存等等
一级缓存 :Session的缓存
它指的是Session对象的缓存,一旦Session对象销毁了,则一级缓存也就消失了
在同一session查询
第一次查询:先去数据库查询,并且把查询的结果存入了一级缓存之中,并且存到快照区。
第二次查询:先去一级缓存查询,如果存在则使用,如果不存在则去数据库查找。
一级缓存存储
快照机制
每次查找先比较缓存区和快照区是否相同,如果不同则先同步数据库
当使用save方法保存后也会在内存中有缓存数据,所以当进行大量数据的保存时可能会造成内存溢出错误
针对session中的缓存提供有三个处理的操作方法,这三个操作方法都在session的接口中定义:
flush方法的主要作用是清理缓存,强制数据库与Hibernate缓存同步,以保证数据的一致性。它的主要动作就是向数据库发送一系列的sql语句,并执行这些sql语句,但是不会向数据库提交。而commit方法则会首先调用flush方法,然后提交事务。这就是为什么我们仅仅调用flush的时候记录并未插入到数据库中的原因,因为只有提交了事务,对数据库所做的更新才会被保存下来。因为commit方法隐式的调用了flush,所以一般我们都不会显示调用flush方法。
二级缓存 :SessionFactory缓存
配置hibernate.cfg.xml文件
<!-- 在配置文件中打开二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 配置二级缓存的处理类 -->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
导入ehcache的jar文件
在工程src目录下创建ehcache的配置文件:ehcache.xml,path路径找不到会导致报错
<ehcache>
<diskStore path="c:/hibernateCache"/>
<defaultCache
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"/>
<cache name="org.haiwen.entity.Goods"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"/>
</ehcache>
对一个实体类进行缓存配置,需要在此类对应的Xxx.hbm.xml文件里面进行缓存配置
<cache usage="read-write"/>
或者
<class-cache usage="read-write" class="org.haiwen.entity.Goods"/>
在实体类上注解使用二级缓存,报错是因为导包不对
@Entity
@Table(name = "goods")
@Cacheable(value = true)
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Goods {
测试
public void list() {
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.getCurrentSession();
session.getTransaction().begin();
List<Goods> goods = session.createCriteria(Goods.class).list();
for (Goods good : goods) {
System.out.println(good.getGoodsName());
}
session.getTransaction().commit();
//以下查询不会发送SQL
Session session2 = factory.getCurrentSession();
session2.getTransaction().begin();
Goods goods2 = (Goods) session2.get(Goods.class, 1);
System.out.println(goods2.getGoodsName());
session2.getTransaction().commit();
}