Hibernate提供了两个缓存级别:
- 一级缓存是会话缓存。 对象被缓存在当前会话中,并且它们仅在会话关闭之前是活动的。
- 只要会话工厂处于活动状态,第二级缓存就存在。 请记住,在Hibernate情况下,二级缓存不是对象树。 对象实例不被缓存,而是存储属性值。
在简要介绍了一下Hibernate缓存之后(让我知道这很简短),让我们看一下什么是查询缓存以及如何与二级缓存相关联。
查询缓存负责将作为参数提供的查询和值的组合作为键进行缓存,并将查询执行返回的对象的标识符列表作为值进行缓存。 注意,使用查询缓存也需要二级缓存,因为从缓存(即标识符列表)获取查询结果时, Hibernate将使用二级缓存的标识符加载对象。
概括起来,作为一个概念性的模式,给出下一个查询:“ from country from country>:number “,第一次执行后, Hibernate缓存将包含下一个虚构值(请注意,number参数设置为1000):
L2快取
[
id:1,{name ='Spain',人口= 1000,...。} id:2,{name ='德国',人口= 2000,...} …。 QueryCache [{来自人口>:number的国家/地区,1000},{id:2}]
因此,在开始使用查询缓存之前,我们需要配置第二级缓存。
首先,您必须确定要使用的缓存提供程序。 对于此示例,选择了Ehcache ,但请参阅Hibernate文档以获取所有支持的提供程序的完整列表。
要配置二级缓存,请设置下一个休眠属性:
hibernate.cache.provider_class = org.hibernate.cache.EhCacheProvider
hibernate.cache.use_structured_entries = true
hibernate.cache.use_second_level_cache = true
如果您使用注释方法,请使用以下方法注释可缓存的实体:
@可缓存
@Cache(用法= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
可以看到在这种情况下,缓存并发策略是NONSTRICT_READ_WRITE ,但是根据缓存提供者的不同,可以遵循其他策略,例如TRANSACTIONAL,READ_ONLY ………请查看Hibernate文档的缓存部分,以选择最适合您需求的策略。
最后添加Ehcache依赖项:
<依赖性>
<groupId> net.sf.ehcache </ groupId>
<artifactId> ehcache-core </ artifactId> <version> 2.5.0 </ version> </ dependency> <依赖性> <groupId> org.hibernate </ groupId> <artifactId> hibernate-ehcache </ artifactId> <version> 3.6.0.Final </ version> </ dependency>
现在已配置了二级缓存,但未配置查询缓存 ; 无论如何,我们离目标不远。
将hibernate.cache.use_query_cache属性设置为true 。
对于每个可缓存的查询,我们必须在查询创建期间调用setCachable方法:
List <Country> list = session.createQuery(“来自人口> 1000的国家/地区”).setCacheable(true).list();
为了使示例更实用,我已经使用Spring Framework上传了完整的查询缓存示例。 为了清楚地了解查询缓存的工作原理,我使用了一个在ensembl.org中托管的公共数据库。 Ensembl项目为脊椎动物和其他真核生物建立了基因组数据库,并在线免费提供此信息。 在此示例中,对dna表的查询被缓存。
首先进行Hibernate配置:
@Configuration
public class HibernateConfiguration {@Value("#{dataSource}")private DataSource dataSource;@Beanpublic AnnotationSessionFactoryBean sessionFactoryBean() {Properties props = new Properties();props.put("hibernate.dialect", EnhancedMySQL5HibernateDialect.class.getName());props.put("hibernate.format_sql", "true");props.put("hibernate.show_sql", "true");props.put("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider");props.put("hibernate.cache.use_structured_entries", "true");props.put("hibernate.cache.use_query_cache", "true");props.put("hibernate.cache.use_second_level_cache", "true");props.put("hibernate.hbm2ddl.auto", "validate");AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();bean.setAnnotatedClasses(new Class[]{Dna.class}); bean.setHibernateProperties(props);bean.setDataSource(this.dataSource);bean.setSchemaUpdate(true);return bean;}}
这是一个简单的Hibernate配置,使用前面说明的属性来配置二级缓存。
实体类是代表DNA序列的实体。
@Entity(name="dna")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Dna {@Idprivate int seq_region_id;private String sequence;public int getSeq_region_id() {return seq_region_id;}public void setSeq_region_id(int seq_region_id) {this.seq_region_id = seq_region_id;}@Columnpublic String getSequence() {return sequence;}public void setSequence(String sequence) {this.sequence = sequence;}}
为了尝试查询缓存 ,我们将实现一项测试,其中多次执行同一查询。
@Autowired
private SessionFactory sessionFactory;@Test
public void fiftyFirstDnaSequenceShouldBeReturnedAndCached() throws Exception {for (int i = 0; i < 5; i++) {Session session = sessionFactory.openSession();session.beginTransaction();Time elapsedTime = new Time("findDna"+i);List<Dna> list = session.createQuery("from dna").setFirstResult(0).setMaxResults(50).setCacheable(true).list();session.getTransaction().commit();session.close();elapsedTime.miliseconds(System.out);for (Dna dna : list) {System.out.println(dna);}}
}
我们可以看到我们正在返回前五十个dna序列,如果执行它,您将看到打印了从查询创建到提交事务之间的经过时间。 如您所料,仅第一次迭代就需要大约5秒钟来获取所有数据,而其他迭代只需数毫秒。
查询迭代之前的foreach行将通过控制台打印对象标识符。 如果仔细观察,这些标识符将不会在所有执行期间重复。 这个事实只是向您显示Hibernate缓存不会保存对象而是保存属性值,并且每次都会创建对象本身。
最后一点,请记住,默认情况下, Hibernate不缓存关联。
现在,在编写查询之后,考虑它是否将包含静态数据以及是否将经常执行。 在这种情况下, 查询缓存是您的朋友,可以使Hibernate应用程序运行得更快。
下载代码
参考:来自JCG合作伙伴的 Hibernate缓存级别教程 在一个罐子统治他们所有博客的亚历克斯·索托。
翻译自: https://www.javacodegeeks.com/2012/02/hibernate-cache-levels-tutorial.html