Hibernate是个ORM框架,ORM框架解决的就是数据库访问的问题,我们评判一个ORM框架是否有优秀,主要看访问数据库的效率。
hibernate使用其缓存机制来提升访问数据库的效率。
缓存机制的基本原理:
对于每次对数据的请求,先去缓存中查找数据,如果命中,则读取数据,若未命中,再到数据库中查找数据,并将数据存入到缓存中,以此来提升访问效率。
Hibernate的一级缓存:
hibernate 的一级缓存又称session缓存,或会话级缓存,它是跟session相关的,当通过session从数据库查询实体时,会把实体在内存中存储起来,下次再查询同一实体时不再去数据库获取数据,而是在内存中获取。
一级缓存的生命周期和session是相同的,session销毁,一级缓存也销毁。
与一级缓存相关的两个方法:
session.evict(之前获取的对象) //用于清除一级缓存中的指定对象
session.clear() //用于清除一级缓存中的所有对象
query两个方法的区别:
query.list()方法不会使用到一级缓存
query.iterate()方法,现在数据库查找数据的主键,再根据主键去缓存中查找数据,未命中再去数据库查找。
tx = session.beginTransaction();
User user1 = (User)session.load(User.class, 1); //下面用到setName,会执行sql语句,getId也会执行
user1.setName("张三");
user1.setName("李四"); //在缓存中进行修改
tx.commit(); //只在事务提交时执行一次update语句
tx = session.beginTransaction();
User user1 = (User)session.load(User.class, 1); //不发送任何sql语句
User user2 = (User) session.load(User.class, 1);
System.out.println(user1==user2); //打印true
tx.commit();//都得到相同的代理对象
Hibernate的二级缓存:
二级缓存是应用级缓存,每个session共用的缓存,
它不是默认开启的,其开启步骤为
1>开启二级缓存
<property name="hibernate.cache.use_second_level_cache">true</property>
2>指定二级缓存的实现类,这里用ehcache
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
3>配置文件位置
<property name="hibernate.cache.provider_configuration_file_resource_path">classpath:ehcache.xml</property>
4>在需要被缓存的表对应的映射文件中添加<cache/>标签
<cache usage="read-only"/> //一般二级缓存都设置为只读
或者用注解的方式,在需要缓存的类上加@Cache
其中关于<cache/>标签的详细介绍 :
usage 指定缓存策略,可用于处理并发问题
region:指定二级缓存域名,可在ehcache的配置文件中进行缓存策略的配置
include: 指定是否缓存延迟加载的对象,all--缓存 non-lazy ----不缓存
try
{
Session session1 = HibernateUtil.getSessionFactory().openSession();
Transaction tx1 = session1.beginTransaction();
User user1 = (User)session1.load(User.class, 1); //下面用到setName,会执行sql语句,getId也会执行
System.out.println(user1.getName());
tx1.commit();
session1.close();
Session session2 = HibernateUtil.getSessionFactory().openSession();
Transaction tx2 = session2.beginTransaction();
User user2= (User)session2.load(User.class, 1); //下面用到setName,会执行sql语句,getId也会执行
System.out.println(user2.getName());
tx2.commit();
session2.close();
}
第二次并没有发送sql语句,二级缓存生效。
二级缓存缓存的仅仅是对象,如果查询出来的是对象的一些属性,则不会被加到缓存中去
Session session1 = HibernateUtil.getSessionFactory().openSession();
Transaction tx1 = session1.beginTransaction();
User user1 = (User)session1.load(User.class, 1); //下面用到setName,会执行sql语句,getId也会执行
System.out.println(user1.getName());
tx1.commit();
session1.close();
Session session2 = HibernateUtil.getSessionFactory().openSession();
Transaction tx2 = session2.beginTransaction();
Object[] obj = (Object[]) session.createQuery(" select u.name,u.sex from User u where u.id=1").uniqueResult();
tx2.commit();
session2.close();
查询缓存:
在配置文件中加入
<property name="hibernate.cache.use_query_cache">true</property>//开启查询缓存
查询缓存能缓存sql语句,只有当sql语句包括变量值完全相同时,才会使用查询缓存
查询缓存也是SessionFactory级别的,他只缓存主键值。可能会引起n+1的问题。所以一般使用查询缓存要配合二级缓存使用。
注意:
缓存也有可能对程序的性能产生影响,原因是当我们对数据库数据进行增删改的时候,同需要对一级缓存进行相应的操作,但总体一级缓存可以提高查询效率。
通常情况下具有以下特点的数据会放到二级缓存中:
1.很少被修改的数据
2.不是很重要的数据,语序出现偶尔的并发
3.不会被并发的数据
4.参考数据