1.Java中的缓存是指的是一组用于提高IO性能的内存地址,它位于JVM中,存储在内存或者磁盘中。
2. 为什么要用Hibernate缓存?
Hibernate是一个持久层框架,经常访问物理数据库。为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据时对物理数据源中的数据的赋值,应用程序在运行时从缓存读写数据,如果缓存中不存在,才会去访问数据库。
3.Hibernate缓存分类
(1) 一级缓存:
是一个线程对应一个session,一个线程可以看成一个用户。也就是说session级缓存只能给一个线程用,别的线程用不了,大家不能共享,总之,一级缓存就是和线程绑定了。一级缓存的生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级的缓存。如果session关闭了,生命九期也就结束了。
(2) 二级缓存:
二级缓存也称为进程级的缓存或sessionFactory级的缓存。二级缓存可以被所有的session共享。二级缓存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二级缓存。
(3)查询缓存:
查询缓存是缓存普通属性结果集的,对实体对象的结果集会缓存id。当关联的表发生修改,查询缓存的生命周期就结束了。
4. 一级缓存
对于Hibernate一级缓存时默认就有的,并且不能卸载。一级缓存的内部结构就是一个map<id,object>,map的key就是id,map 的value就是实体对象,所以一级缓存缓存的是实体对象,不能缓存属性。
hibernate是一个线程对应一个session,一个线程可以看成一个用户。也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了。hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存。如果tb事务提交或回滚了,我们称session就关闭了,生命周期结束了。
下面我们来看写一下测试代码:
classes类:
package com.lsh.hibernate;
import java.util.Set;
public class Classes {
private int id;
private String name;
private Set students;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
Junit测试类:
package com.lsh.hibernate;
import java.io.Serializable;
import java.util.Iterator;
import org.hibernate.Session;
import junit.framework.TestCase;
public class CacheTest extends TestCase {
/**
* 在同一个session中发出两次load查询
*/
public void testCache1(){
Session session =null;
try {
session =HibernateUtils.getSession();
session.beginTransaction();
Student student =(Student)session.load(Student.class, 10);
System.out.println("student.name=" + student.getName());
//不会发出查询语句,load使用缓存
student=(Student)session.load(Student.class, 10);
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
/**
* 在同一个session中发出两次get查询
*/
public void testCache2(){
Session session =null;
try {
session =HibernateUtils.getSession();
session.beginTransaction();
Student student =(Student)session.get(Student.class, 1);
System.out.println("student.name=" + student.getName());
//不会发出查询语句,get使用缓存
student=(Student)session.get(Student.class, 1);
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
/**
* 在同一个session中发出两次iterate查询,查询实体对象
*/
public void testCache3(){
Session session =null;
try {
session =HibernateUtils.getSession();
session.beginTransaction();
Iterator iter = session.createQuery("from Student s where s.id<10").iterate();
while (iter.hasNext()) {
Student student = (Student) iter.next();
System.out.println(student.getName());
}
System.out.println("_______________________________");
//它会发出查询id的语句,但不会发出根据id查询学生的语句,因为iterate使用缓存
iter=session.createQuery("from Student s where s.id<10").iterate();
while (iter.hasNext()) {
Student student = (Student) iter.next();
System.out.println(student.getName());
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
/**
* 在两个session中发出iterate查询,查询普通属性
*/
public void testCache4(){
Session session =null;
try {
session =HibernateUtils.getSession();
session.beginTransaction();
Iterator iter = session.createQuery("select s.name from Student s where s.id<5").iterate();
while (iter.hasNext()) {
String name = (String) iter.next();
System.out.println(name);
}
System.out.println("_______________________________");
//iterate查询普通属性,一级缓存不会缓存,所以发出查询语句
//一级缓存是缓存实体对象的
iter=session.createQuery(" select s.name from Student s where s.id<5").iterate();
while (iter.hasNext()) {
String name = (String) iter.next();
System.out.println(name);
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
/**
* 在同二个session中发出load查询
*/
public void testCache5(){
Session session =null;
try {
session =HibernateUtils.getSession();
session.beginTransaction();
Student student =(Student)session.load(Student.class, 10);
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
try {
session =HibernateUtils.getSession();
session.beginTransaction();
//会发出查询语句,session间不能共享一级缓存数据
//因为他会伴随着session的消亡而消亡
Student student =(Student)session.load(Student.class, 10);
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
/**
* 在同一个session中先调用save,再调用load查询刚刚save的数据
*/
public void testCache6(){
Session session=null;
try {
session=HibernateUtils.getSession();
session.beginTransaction();
Student student =new Student();
student.setName("张三");
Serializable id =session.save(student);
student=(Student)session.load(Student.class, id);
//不会发出查询语句,因为save支持缓存
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
/**
* 大批量的数据添加,如果放大量的缓存会溢出,定期清理一下缓存
*/
public void testCache7(){
Session session=null;
try {
session=HibernateUtils.getSession();
session.beginTransaction();
for (int i = 0; i <100; i++) {
Student student =new Student();
student.setName("张三" +i);
session.save(student);
if (i%20==0) {
//执行sql语句,相当于把这些缓存全部保存到数据库中了
session.flush();
//清楚缓存的内容
session.clear();
}
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
下面是对上面代码的提取总结:
因为Session的生命周期往往很短,存在于Session内部的第一集最快缓存的生命周期也是很短的,所以一级缓存的命中率很低的。其对系统性能的改善也是很有限的。当然,这个session内部缓存的主要作用是保持session内部数据状态同步,并非是hibernate为了大幅提高系统性能所提供的。
为了提高使用hibernate的性能,除了常规的一些需要注意的方法,如:用延迟加载、迫切外链接、查询过滤等以外,还需要配置hibernate的二级缓存。其对系统性能的改善往往立竿见影。下篇我就来介绍一下二级缓存。