您的位置:首页 > 其它

Hibernate缓存的evict、clear和flush方法

2016-03-27 19:24 429 查看
evict()、clear()和flush()方法是Hibernate缓存的3种基本操作方法,本文主要介绍这3种方法的使用方式和具体区别。
Company表:

Company实体类:
import java.util.Set;

public class Company {
private int companyId;
private String companyName;
private Set<Employee> companyEmployees;
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Set<Employee> getCompanyEmployees() {
return companyEmployees;
}
public void setCompanyEmployees(Set<Employee> companyEmployees) {
this.companyEmployees = companyEmployees;
}
}
Company hbm配置:
<hibernate-mapping>
<class name="com.jaeger.hibernatetest.day7.lazy.Company" table="company">
<id name="companyId" column="company_id">
<generator class="native"></generator>
</id>

<property name="companyName" column="company_name"/>
<set name="companyEmployees">
<key column="employee_company_id"></key>
<one-to-many class="com.jaeger.hibernatetest.day7.lazy.Employee"/>
</set>
</class>
</hibernate-mapping>
1. evict()和clear()方法
evict()和clear()方法都是从session中清除缓存,evict()是清除单个对象的缓存,而clear()是清除所有缓存。测试方法如下:

Company company = (Company)session.get(Company.class, 1); //A
System.out.println(company.getCompanyName()); //B
company = (Company)session.get(Company.class, 1);  //C
System.out.println(company.getCompanyName()); //D
A:此处发出SQL去数据库查询。
B:此处打印出:KONAMI。
C:此处取缓存,不会发SQL。
D:此处打印出:KONAMI。
下面我们在第二次get之前先清除缓存:

Company company = (Company)session.get(Company.class, 1); //A
System.out.println(company.getCompanyName());
session.evict(company); //B
company = (Company)session.get(Company.class, 1);  //C
System.out.println(company.getCompanyName());
A、C:这两处都会发相同的SQL去数据库查询。因为B处清除了缓存,调用clear()方法效果也是一样。

2. flush()方法
flush()方法会根据缓存中对象的操作生成相应的SQL语句去操作数据库。没有调用flush()的测试方法如下:
Company company = (Company)session.get(Company.class, 1);
company.setCompanyName("Santa Monica");
session.update(company); //A

Company newCompany = new Company();
newCompany.setCompanyName("UBISOFT");
session.save(newCompany); //B
transaction.commit(); //C
session.close();
A:此处不会发出SQL去更新数据库。
B:此处会发出insert语句去更新数据库,但数据是未提交的状态,如果数据库的隔离级别是Read Committed的话就可以看到。
insert
into
company
(company_name)
values
(?)
C:此处会发出update语句去更新company信息。
update
company
set
company_name=?
where
company_id=?
这里之所以会发出SQL语句,因为transaction.commit()会调用flush()方法。
下面我们自己来调用flush()方法:
Company company = (Company)session.get(Company.class, 1);
company.setCompanyName("Santa Monica");
session.update(company);
session.flush(); //A

Company newCompany = new Company();
newCompany.setCompanyName("UBISOFT");
session.save(newCompany);
transaction.commit(); //B
session.close();
A:此处立刻会发出update语句去更新company信息。数据是未提交的状态。
B:此处会发出insert语句去更新数据库。数据是未提交的状态。

注意:Hibernate使用的主键生成策略为uuid时情况会有所不同,我们把Company实体类的companyId属性的类型改为String,再把Company hbm配置修改为<generator class="uuid">。下面还是使用上面的测试方法:
Company company = (Company)session.get(Company.class, 1);
company.setCompanyName("Santa Monica");
session.update(company); //A

Company newCompany = new Company();
newCompany.setCompanyName("UBISOFT");
session.save(newCompany); //B
transaction.commit(); //C
session.close();
A、B:这时update()和save()都不会向数据库发SQL语句,第一次测试中save()方法会发SQL语句是因为我们使用的是native主键生成策略,要拿到主键就必须先向数据库插入数据。而uuid是Hibernate自己生成的,所以只会加入缓存,而不会发出SQL语句。

C:这个地方很关键,我们先看看Hibernate生成的SQL语句:

insert
into
company
(company_name, company_id)
values
(?, ?)

update company set company_name=? where company_id=?
从上面可以看出:Hibernate在用缓存中的对象去操作数据库时,并不是按照我们程序的顺序去执行,而是先执行insert,然后才执行update和delete。这就有可能让执行结果跟我们所期待的不一样。这个时候就应该使用flush()方法手动的让Hibernate及时去发送SQL语句。上面的例子中,我们如果在A步骤后面加入session.flush()方法,则update就会比insert先执行。
本文出自 “銅鑼衛門” 博客,请务必保留此出处http://jaeger.blog.51cto.com/11064196/1757270
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: