Hibernate一级缓存

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate一级缓存相关的知识,希望对你有一定的参考价值。

Hibernate一级缓存又称为“Session的缓存”。Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事务)。一级缓存中,持久化类的每个实例都具有唯一的OID。下面我们用实例来看看Hibernate一级缓存的使用:

Employee表(employee_company_id为外键)

技术分享

Employee实体类:

public class Employee {
    private int employeeId;
    private String employeeName;
    private Company employeeCompany;
    public int getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }
    public String getEmployeeName() {
        return employeeName;
    }
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    public Company getEmployeeCompany() {
        return employeeCompany;
    }
    public void setEmployeeCompany(Company employeeCompany) {
        this.employeeCompany = employeeCompany;
    }
}

Employee hbm配置:

<hibernate-mapping>
    <class name="com.jaeger.hibernatetest.day7.lazy.Employee" table="employee">
       <id name="employeeId" column="employee_id">
         <generator class="native"></generator>
     </id>

        <property name="employeeName" column="employee_name"/>
        <many-to-one name="employeeCompany" class="com.jaeger.hibernatetest.day7.lazy.Company" 
            foreign-key="fk_employee_company" column="employee_company_id"
            cascade="save-update">
        </many-to-one>
   </class>
</hibernate-mapping>

1. get()和load()方法
get()和load()方法对session缓存的处理方式是一致的,所以下面以get()方法为例。测试方法如下:

Employee employee = (Employee)session.get(Employee.class, 1); //A
System.out.println(employee.getEmployeeName()); //B
employee = (Employee)session.get(Employee.class, 1); //C
System.out.println(employee.getEmployeeName()); //D

A、B:如果是get()方法在A处就发SQL语句去数据库查询,如果是load()方法又支持延迟加载的话在B处才发SQL语句去数据库查询。SQL如下:

select
     employee0_.employee_id as employee1_1_0_,
     employee0_.employee_name as employee2_1_0_,
     employee0_.employee_company_id as employee3_1_0_ 
  from
     employee employee0_ 
 where
     employee0_.employee_id=?

C:此处我们用Hibernate又去查询了一次,但此处不会再发出SQL去数据库查询,因为在A处get和load时已经把对象加入了session缓存,所以直接返回session缓存里面的对象。


2. list()和uniqueResult()方法
list()和uniqueResult()方法对session缓存的处理方式是一致的,所以下面以list()方法为例。测试方法如下:

List<Employee> allEmployees = session.createQuery("from Employee").list(); //A
System.out.println(allEmployees.size());
allEmployees = session.createQuery("from Employee").list(); //B
System.out.println(allEmployees.size());

A:此处会发SQL语句去数据库查询。SQL如下:

select
     employee0_.employee_id as employee1_1_,
     employee0_.employee_name as employee2_1_,
     employee0_.employee_company_id as employee3_1_ 
  from
     employee employee0_

B:这里也会发上面相同的SQL去数据库查询。说明list()方法并不会去session缓存里面找,而是直接去数据库查询。

但list()方法会把查询出来的实体对象放入session缓存,如果后面使用get()或者load()方法就可以从session缓存里面拿。具体测试方法如下:

List<Employee> allEmployees = session.createQuery("from Employee").list(); //A
System.out.println(allEmployees.size());
Employee employee = (Employee)session.get(Employee.class, 1); //B
System.out.println(employee.getEmployeeName());

A:此处会发上面相同的SQL去数据库查询,并把查询出来的对象放入session缓存。
B:此处并不会再发出SQL语句,因为session缓存里已经有了id为1的Employee对象,就直接从缓存里面拿。load()方法也是一样。

注意上面所说的实体对象,如果采用‘from Employee‘这种HQL查询出来的就是实体对象,但如果采用查询字段的方式,如:‘select employeeId, employeeName, employeeCompany from Employee‘,虽然也拿出了employee表的所有字段,但不会放入session缓存。测试方法如下:

List<Employee> allEmployees = session.createQuery("select employeeId, employeeName, employeeCompany from Employee").list(); //A
System.out.println(allEmployees.size());
Employee employee = (Employee)session.get(Employee.class, 1); //B
System.out.println(employee.getEmployeeName());

A:此处会发SQL语句去数据库查询。SQL如下:

select
     employee0_.employee_id as col_0_0_,
     employee0_.employee_name as col_1_0_,
     employee0_.employee_company_id as col_2_0_,
     company1_.company_id as company_1_0_,
     company1_.company_name as company_2_0_ 
  from
     employee employee0_ 
 inner join
     company company1_ 
    on employee0_.employee_company_id=company1_.company_id

B:此处会再向数据库发SQL语句,也就是没有去使用session缓存。SQL如下:

select
     employee0_.employee_id as employee1_1_0_,
     employee0_.employee_name as employee2_1_0_,
     employee0_.employee_company_id as employee3_1_0_ 
  from
     employee employee0_ 
 where
     employee0_.employee_id=?

3. iterate()方法
测试方法如下:

Iterator<Employee> allEmployees = session.createQuery("from Employee").iterate(); //A
while(allEmployees.hasNext()){
    Employee employee = allEmployees.next();
    System.out.println(employee.getEmployeeName()); //B
}
allEmployees = session.createQuery("from Employee").iterate(); //C
while(allEmployees.hasNext()){
    Employee employee = allEmployees.next();
    System.out.println(employee.getEmployeeName()); //D
}

iterate()方法最大的特点就是查询N+1次,第一次查询出所有的OID,然后通过OID去查询其他的属性字段。
A:此处会发出SQL语句去数据库查询所有的OID,SQL如下:

select
     employee0_.employee_id as col_0_0_ 
  from
     employee employee0_

B:此处会根据OID循环发出SQL语句去数据库查询对应的实体对象,其中一条SQL如下:

select
     employee0_.employee_id as employee1_1_0_,
     employee0_.employee_name as employee2_1_0_,
     employee0_.employee_company_id as employee3_1_0_ 
  from
     employee employee0_ 
 where
     employee0_.employee_id=?

C:此处发出跟A一样的SQL语句去数据库查询所有的OID。
D:这里不会再循环发出SQL语句去数据库查询对应的实体对象,而是直接从session缓存里面取。如果用get()和load()方法也会优先从session缓存里面取。

iterate()方法跟list()方法一样,如果采用‘from Employee‘这种HQL查询出来的就是实体对象,但如果采用查询字段的方式,如:‘select employeeId, employeeName, employeeCompany from Employee‘,虽然也拿出了employee表的所有字段,但不会放入session缓存。

还有一点区别是,查询实体对象iterate()方法返回的是Employee的代理对象;如果采用查询字段的方式,iterate()方法返回的却是Object数组,测试方法如下:

Iterator<Object[]> allEmployees = session.createQuery("select employeeId, employeeName,
    employeeCompany from Employee").iterate(); //A
while(allEmployees.hasNext()){
    Object[] employee = allEmployees.next();
    System.out.println(employee[0]); //B
    System.out.println(employee[1]); //C
    System.out.println(employee[2]); //D
}
Employee employee = (Employee)session.get(Employee.class, 1); //E
System.out.println(employee.getEmployeeName());

A:这里会向数据库发出SQL语句,但会查出employeeId, employeeName, employeeCompany三个字段,而不仅仅查出OID(employeeId)。SQL如下:

select
     employee0_.employee_id as col_0_0_,
     employee0_.employee_name as col_1_0_,
     employee0_.employee_company_id as col_2_0_ 
  from
     employee employee0_,
     company company1_ 
 where
     employee0_.employee_company_id=company1_.company_id

这里连接了company表,但实际上是多余的。
B、C:这里会打印出employeeId和employeeName。
D:此处会向数据库发送SQL语句用employee_company_id去查关联的company的信息。SQL如下:

select
     company0_.company_id as company_1_0_0_,
     company0_.company_name as company_2_0_0_ 
  from
     company company0_ 
 where
     company0_.company_id=?

E:此处会重新向数据库发送SQL语句,说明这种iterate查询并不会把查询结果放到session缓存。SQL如下:

select
     employee0_.employee_id as employee1_1_0_,
     employee0_.employee_name as employee2_1_0_,
     employee0_.employee_company_id as employee3_1_0_ 
  from
     employee employee0_ 
 where
     employee0_.employee_id=?


本文出自 “銅鑼衛門” 博客,请务必保留此出处http://jaeger.blog.51cto.com/11064196/1753689

以上是关于Hibernate一级缓存的主要内容,如果未能解决你的问题,请参考以下文章

hibernate笔记--缓存机制之 一级缓存(session缓存)

Hibernate缓存总结

Hibernate一级缓存

hibernate 一级缓存和二级缓存

hibernate一级和二级缓存介绍

Hibernate一级缓存