Hibernate缓存级别教程

开始使用Hibernate的人们常见的问题之一就是性能,如果您没有太多的Hibernate经验,您会发现应用程序变慢的速度。 如果启用sql跟踪,您将看到有多少查询被发送到数据库,而这些查询几乎不需要Hibernate知识就可以避免。 在当前文章中,我将解释如何使用休眠查询缓存来避免应用程序和数据库之间的通信量。

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;

 @Bean
 public 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 {

 @Id
 private 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;
 }

 @Column
 public 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值