Hibernate 缓存 之 Session 实现(二)

一级缓存: Session 级共享,此缓存只能在 Session 关闭之前使用.save, update, saveOrUpdate, get, list, iterate, lock 这些方法都会将对象放在一级缓存中, 一级缓存不能控制缓存的数量, 所以,要注意大批量操作数据时可能造成内在溢出。可以用evict, clear方法清除缓存中的内容.后面 Hibernate 批量增加数据时再演示。
二级缓存: SessionFactory 级共享,实现为可插拔,通过修改两个开关来改变.
首先,告诉 Hibernate,我现在要使用缓存机制:
<property name="hibernate.cache.use_second_level_cache">true</property>

配置二级缓存的提供者,也就是具体厂商提供的实现类

<property name="cache.provider_class">

缓存的配置,可以在Hibernate源码包下查找hibernate.properties这个文件,找到 Second-level Cache 这一块,可以看到所有的配置项
#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider

hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider
可以看到缓存的实现有很多种,那么怎么选择呢?这需要看你的 jar 包中有哪个对应的缓存实现包,我们可以 导到 我们的 Hibernate 库下
可以看到有一个 ehcache-1.2.3.jar 包,那么这个时候,我们可以选择使用 org.hibernate.cache.EhCacheProvider 这个实现类,
我们可以在我们的 Hibernate.cfg.xml 中加入下面的配置项.
<pre name="code" class="html"><property name="hibernate.cache.use_second_level_cache">true</property>
<property name="cache.provider_class">
	org.hibernate.cache.EhCacheProvider
</property>
 接下来,我们还需要告诉 Hibernate 哪些类需要缓存,还需要在 Hibernate.cfg.xml 中加入下面的配置项.<class-cache usage="read-only" class="chapter1.model.Student"/>usage="read-only"指 
  缓存的策略,有以下几种策略:read-only是不允许修改缓存,效率最高,通常用到像新闻的分类啊,省市联动等等一些不会改变的信息.read-write,像经常需要改动的,可以使用read-write策略,此策略是线程同步nonstrict-read-write,策略和上面一样,但是线程不同步.transactional,事务策略,如果产生错误,缓存会回滚,实现非常复杂.还有一种方式配置告诉Hibernate 
 哪些类需要缓存, 不需要在Hibernate.cfg.xml配置,直接在Student.hbm.xml中配置即可(推荐方法) 
 
<pre name="code" class="html"><class name="chapter1.model.Student" table="students">
	<cache usage="read-only" />
	<id name="id" type="java.lang.String">
		<column name="id" length="32" />
		<generator class="uuid.hex" />
	</id>
	<property name="name" type="java.lang.String">
	<column name="name" length="20" />
	</property>
	<many-to-one name="myClass" class="chapter1.model.MyClass">
		<column name="student_id" length="32" />
	</many-to-one>
</class>
 在id前面加上<cache usage="read-only" />, 这就不需要告诉类名了.再次执行Test类的main方法,可以看到只执行了一条SQL语句 
 Query的查询缓存首先打开<property name="hibernate.cache.use_query_cache">true</property>修改StudentDao层,添加一个 findAll() 方法 
 
<pre name="code" class="java">public List<Student> findAll() throws Exception {
	Session session = null;
	Transaction transaction = null;
	List<Student> students = null;
	try {
		session = HibernateUtil.getSession();
		transaction = session.getTransaction();
		transaction.begin();
		Query query = session.createQuery("from Student");
		query.setCacheable(true);
		students = query.list();
		transaction.commit();
	} catch (Exception e) {
		transaction.rollback();
		throw e;
	}
	return students;
}
 注意这里有一句 query.setCacheable(true); //设置缓存开关,使其起作用再来执行Test的main方法: 
 
<pre name="code" class="java">public class Test {
	public static void main(String[] args) throws Exception {
	   MyClassDao myClassDao = new MyClassDao();
	   StudentDao studentDao = new StudentDao();
	   List<Student> students1 = studentDao.findAll();
	   List<Student> students2 = studentDao.findAll();  
       }
}
 可以看到只执行了一句select语句. 
 查询的击中执行下面的代码: 
 
<pre name="code" class="java">List<Student> students1 = studentDao.findAll();
System.out.println("查询所有学生");
for (Student s : students1) {
	System.out.println(s.getName());
}
 
 
Student student = studentDao.findById("4028810027d8be080127d8be0d790003");
System.out.println(student.getName());

可以看到只执行了一条SQL语句,

studentDao.findById("4028810027d8be080127d8be0d790003");

这句代码的查询并没有执行.当Hibernate执行完了

Query query = session.createQuery("from Student")

类似于这种查询以后,会将查询结果存放起来,Hibernate存放的时候会这样存放

map.put (“复杂的key值”, 对象的Id)

所以当你执行按ID查询时,就会先从缓存中查询,这时就会被命中了.


使用缓存时需要注意的几点地方:
读取次数大于修改次数,即不是经常修改的数据进行缓存
缓存的容量不能大于内存
对数据要有独享的控制权,即只能通过我这里操作数据,不能从其它通道操作数据
可以容忍无效的数据出现

你可能感兴趣的:(Hibernate,session,一级缓存,二级缓存,查询缓存)