(1)Hibernate 一级缓存又称之为"Session 缓存"、“会话级缓存”
(2)通过Session从数据库查询时会吧实体在内存中存储起来,下一次查询同一实体时不再从数据库获取,而是从内存中获取,这就是缓存。
(3)一级缓存的生命周期和session相同;Session 销毁它也会销毁
(4)一级缓存中的数据可适用范围在当前会话之内
一级缓存无法取消,用两个方法管理。
(1)session.evict(obj) :会把指定的缓冲对象进行清除。
(2) session.clear() :把缓冲区内的全部对象清除,但不包括操作中的对象。
测试用例1session.evict(obj) 清理当前对象后,再次查询需要查询数据库:
测试用例2 session.clear 后(需要从数据库中查询):
(1)query.list()是不会使用一级缓存的
(2)query.iterate()会使用一级缓存,当缓存中有数据的时候,query.iterate()将所有对象的id查询出来然后到缓存中将所有对象都查询出来,如果缓存中没有数据,query.iterate()则把对象从数据库中一条一条的将数据查出来
(3)一级缓存也有些时候会对程序的性能产生影响,因为在对数据库进行增删改的时候同时也要更新缓存
测试用例2 query.iterate()会使用一级缓存:
我们看到,当如果通过iterator()方法来获得我们对象的时候,hibernate首先会发出1条sql去查询出所有对象的 id 值,当我们如果需要查询到某个对象的具体信息的时候,hibernate此时会根据查询出来的 id 值再发sql语句去从数据库中查询对象的信息,这就是典型的 N+1 的问题。
二级缓存的生命周期是SessionFactory,当SessionFactory关闭时,缓存才会清空.
二级缓存是每个session共用的缓存,并不是默认开启的,需要手动去配置.
1.添加二级缓存对应的jar包.
jar包:commons-logging-1.1.3.jar、ehcache.jar
2.在Hibernate的配置文件中添加Provider类的描述(即添加二级缓存接口对应外部的实现类).
net.sf.ehcache.hibernate.EhCacheProvider
<property name="hibernate.cache.use_second_level_cache">trueproperty>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactoryproperty>
<property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xmlproperty>
3.添加二级缓存的属性配置文件,直接放在src根目录即可.
ehcache.xml
<ehcache>
<diskStore path="user.dir"/>
<cache name="com.xiaoluo.bean.Student"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/> -->
ehcache>
4.如果使用xml配置,我们需要在 Student.hbm.xml 中加上一下配置。在需要被缓存的表所对应的映射文件中添加标签.
在标签下添加
<hibernate-mapping package="com.xiaoluo.bean">
<class name="Student" table="t_student">
<cache usage="read-only"/>
<id name="id" type="int" column="id">
<generator class="native"/>
id>
<property name="name" column="name" type="string">property>
<property name="sex" column="sex" type="string">property>
<many-to-one name="room" column="rid" fetch="join">many-to-one>
class>
hibernate-mapping>
如果使用annotation配置,我们需要在Student这个类上加上这样一个注解:
@Entity
@Table(name="t_student")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY) // 表示开启二级缓存,并使用read-only策略
public class Student
{
private int id;
private String name;
private String sex;
private Classroom room;
.......
}
(1)二级缓存的使用策略一般有这几种:read-only、nonstrict-read-write、read-write、transactional。注意:我们通常使用二级缓存都是将其配置成 read-only ,即我们应当在那些不需要进行修改的实体类上使用二级缓存,否则如果对缓存进行读写的话,性能会变差,这样设置缓存就失去了意义。
(2)二级缓存缓存的仅仅是对象,如果查询出来的是对象的一些属性,则不会被加到缓存中去
(3)当我们如果通过 list() 去查询两次对象时,二级缓存虽然会缓存查询出来的对象,但是我们看到发出了两条相同的查询语句,这是因为二级缓存不会缓存我们的hql查询语句,要想解决这个问题,我们就要配置我们的查询缓存了。
(4)查询缓存(sessionFactory级别)
我们如果要配置查询缓存,只需要在hibernate.cfg.xml中加入一条配置即可:
<property name="hibernate.cache.use_query_cache">trueproperty>
然后我们如果在查询hql语句时要使用查询缓存,就需要在查询语句后面设置这样一个方法:
List<Student> ls = session.createQuery("from Student where name like ?")
.setCacheable(true) //开启查询缓存,查询缓存也是SessionFactory级别的缓存
.setParameter(0, "%王%")
.setFirstResult(0).setMaxResults(50).list();
如果是在annotation中,我们还需要在这个类上加上这样一个注解:@Cacheable
https://www.cnblogs.com/xiaoluo501395377/p/3377604.html
https://www.imooc.com/learn/465
米宝窝 https://rocklei123.github.io/