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
原文地址:http://jaeger.blog.51cto.com/11064196/1753689