最近学习的缓存,感觉有了进一步的认识,也感觉到自己只是浅浅的利用缓存,如果真正能够的能够优化hibernate的性能,还需要更加深入(对于项目而言)
好了废话不说了。
讲到Hibernate的二级缓存,当时我在想为什么要有二级缓存?二级缓存的用途是什么呢?有人肯定说缓存就是在磁盘存放临时数据嘛。其实大概的意思的确是。
但是我们仔细想想,当开启一个session去读取一个一条数据的时候(load),如果再发一条load,则必然不会发送两条SQL语句,因为session的一级缓存
从内存读取了相应的缓存记录。如果session一级缓存检索几条记录还行,那上百条,上万条,甚至是几十万条,这个内存可想而知。还有就是每个session之间
的数据是不能共享的。于是我们引入二级缓存,解决了上面的两种问题。这个对于数据的检索得到了大大的优化。接下来看一个例子。
使用二级缓存的方法是:在hibernate.cfg.xml中添加一个启动缓存的配置,<property name="cache.use_second_level_cache">true</property>,添加一个二级缓存的
提供者 <property name="hibernate.cache.region.factory_class"> net.sf.ehcache.hibernate.EhCacheRegionFactory</property>(我用的是hiberanet3.0的)
我们现在看的是一个双向一对多的关系,所以缓存配置就更简单了
@Entity
@Table(name="t_department")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Department implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = 1853313501485307077L;
private Integer id;
private String deptName;
private Set<Employee> employees = new HashSet<Employee>();
public Department(){
}
public Department(Integer id,String deptName){
this.id = id;
this.deptName = deptName;
}
public Department(Integer id,String deptName,Set<Employee> employeess){
this.id = id;
this.deptName = deptName;
this.employees = employeess;
}
@Id
@GeneratedValue(generator="generator")
@GenericGenerator(name="generator",strategy="native")
@Column(name="id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="dept_name")
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@OneToMany(mappedBy="department",cascade=CascadeType.ALL)
@BatchSize(size=5)
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
@Entity
@Table(name="t_employee")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Employee implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = 8568295685039740847L;
private Integer id;
private String empName;
private Department department;
public Employee(){
}
@Id
@GeneratedValue(generator="generator")
@GenericGenerator(name="generator",strategy="native")
@Column(name="id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="emp_name")
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@ManyToOne()
@JoinColumn(name="dep_id")
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
单元测试:
@Test
public void testQuery() {
Department department = (Department) session.get(Department.class, 1);
System.out.println(department.getDeptName());
session.close();
session = sessionFactory.openSession();
Department department2 = (Department) session.get(Department.class, 1);
System.out.println(department2.getDeptName());
session.close();
session = sessionFactory.openSession();
Department department3 = (Department) session.get(Department.class, 1);
System.out.println(department3.getDeptName());
session.close();
session = sessionFactory.openSession();
Department department4 = (Department) session.get(Department.class, 1);
System.out.println(department4.getDeptName());
session.close();
System.out.println("sesseionFactory即将关闭");
sessionFactory.close();
}
在打印语句处设置断点,hiberante的二级缓存的生命周期是sessionFactory级别的,所以我们sessionFacory.close()执行后,缓存也会被清除,为此,
我们要加断点。
测试结果显示,只是发送了1条语句,这就是缓存的效果,他们会帮我们第一次查询数据缓,如果下一次,执行相同的查询则不发一条语句。
当进行查询的是一个list的话,只会填充缓存,为此我们需要在添加一个配置查询缓存<property name="cache.use_query_cache">true</property> 这样可以解决
还有就是要注意的是,如果是接下来的这种情况,我们就需要注意的是,在一个事务范围内,如果将一个数据作update的操作(被缓存的一条数据),
则,下一次执行相同查询的时候会发现没有该条记录,缓存会帮我们删除该条记录,我也觉得很奇怪,为什么要这样,hibernate的内部就是这样操作,
至于为什么我们以后再说。先看代码。
public void testQuery2() {
Query query = session.createQuery("from Employee");
query.setCacheable(true);
List<Employee> departments = query.list();
System.out.println(departments.size());
Employee employee = (Employee) session.get(Employee.class, 1);
employee.setEmpName("哈喽");
Criteria criteria = session.createCriteria(Employee.class);
criteria.setCacheable(true);
departments = criteria.list();
System.out.println(departments.size());
}
代码结果显示:第一次显示的department.size()的结果为:4,在这个事务中进行修改某个数据,第二次显示的department.size()变为:3。
总结:hiberante 的list ,iterator,load,get都会填充缓存,但是list不会使用缓存,使用缓存的话需要添加查询缓存。
并且每次查询的时候要添加如:query.setCacheable(true)获取criter.setCacheable(true)
有不对的地方还请读者们不吝赐教,共同进步。