介绍

既然我已经介绍了实体和集合缓存,现在该研究查询缓存的工作原理了。

查询缓存与实体严格相关,它在搜索条件和满足该特定查询过滤器的实体之间绘制关联。 像其他Hibernate功能一样,查询缓存也不像人们想象的那么琐碎。

实体模型

对于我们的测试用例,我们将使用以下域模型:

Post实体与Author 具有多对一关联,并且两个实体都存储在第二级缓存中。

启用查询缓存

默认情况下,查询缓存处于禁用状态,要激活它,我们需要提供以下Hibernate属性:

properties.put("hibernate.cache.use_query_cache", Boolean.TRUE.toString());

为了使Hibernate缓存给定的查询结果,我们需要在创建Query时显式设置cachable查询属性 。

直读缓存

查询缓存是只读的 ,就像NONSTRICT_READ_WRITE并发策略一样 ,它只能使陈旧的条目无效。

在下一个示例中,我们将缓存以下查询:

private List<Post> getLatestPosts(Session session) {return (List<Post>) session.createQuery("select p " +"from Post p " +"order by p.createdOn desc").setMaxResults(10).setCacheable(true).list();
}

首先,我们将使用以下测试案例来研究查询缓存的内部结构:

doInTransaction(session -> {LOGGER.info("Evict regions and run query");session.getSessionFactory().getCache().evictAllRegions();assertEquals(1, getLatestPosts(session).size());
});doInTransaction(session -> {LOGGER.info("Check get entity is cached");Post post = (Post) session.get(Post.class, 1L);
});doInTransaction(session -> {LOGGER.info("Check query result is cached");assertEquals(1, getLatestPosts(session).size());
});

该测试生成以下输出:

QueryCacheTest - Evict regions and run queryStandardQueryCache - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
EhcacheGeneralDataRegion - Element for key sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
is null
StandardQueryCache - Query results were not found in cacheselectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_
fromPost querycache0_
order byquerycache0_.created_on desc limit 10StandardQueryCache - Caching query results in region: org.hibernate.cache.internal.StandardQueryCache; timestamp=5872026465492992
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
value: [5872026465492992, 1]JdbcTransaction - committed JDBC Connection------------------------------------------------------------QueryCacheTest - Check get entity is cachedJdbcTransaction - committed JDBC Connection------------------------------------------------------------QueryCacheTest - Check query is cachedStandardQueryCache - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
StandardQueryCache - Checking query spaces are up-to-date: [Post]EhcacheGeneralDataRegion - key: Post
UpdateTimestampsCache - [Post] last update timestamp: 5872026465406976, result set timestamp: 5872026465492992
StandardQueryCache - Returning cached query resultsJdbcTransaction - committed JDBC Connection
  • 清除所有缓存区域,以确保缓存为空
  • 运行查询后,查询缓存将检查以前存储的结果
  • 因为没有缓存条目,所以查询转到数据库
  • 所选实体和查询结果均被缓存
  • 然后,我们验证Post实体是否存储在二级缓存中
  • 后续查询请求将从缓存中解决,而无需访问数据库

查询参数

查询参数嵌入在缓存条目键中,如以下示例所示。

基本类型

首先,我们将使用基本的类型过滤:

private List<Post> getLatestPostsByAuthorId(Session session) {return (List<Post>) session.createQuery("select p " +"from Post p " +"join p.author a " +"where a.id = :authorId " +"order by p.createdOn desc").setParameter("authorId", 1L).setMaxResults(10).setCacheable(true).list();
}
doInTransaction(session -> {LOGGER.info("Query cache with basic type parameter");List<Post> posts = getLatestPostsByAuthorId(session);assertEquals(1, posts.size());
});

查询缓存条目如下所示:

EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ inner joinAuthor querycache1_ on querycache0_.author_id=querycache1_.id wherequerycache1_.id=? order byquerycache0_.created_on desc;parameters: ; named parameters: {authorId=1}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
value: [5871781092679680, 1]

该参数存储在高速缓存条目键中。 缓存条目值的第一个元素始终是结果集的获取时间戳。 以下元素是此查询返回的实体标识符。

实体类型

我们还可以使用实体类型作为查询参数:

private List<Post> getLatestPostsByAuthor(Session session) {Author author = (Author) session.get(Author.class, 1L);return (List<Post>) session.createQuery("select p " +"from Post p " +"join p.author a " +"where a = :author " +"order by p.createdOn desc").setParameter("author", author).setMaxResults(10).setCacheable(true).list();
}
doInTransaction(session -> {LOGGER.info("Query cache with entity type parameter");List<Post> posts = getLatestPostsByAuthor(session);assertEquals(1, posts.size());
});

缓存条目与我们之前的示例相似,因为Hibernate仅将实体标识符存储在缓存条目键中。 这很有意义,因为Hibernate已经缓存了Author实体。

EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ inner joinAuthor querycache1_ on querycache0_.author_id=querycache1_.id wherequerycache1_.id=? order byquerycache0_.created_on desc;parameters: ; named parameters: {author=1}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
value: [5871781092777984, 1]

一致性

HQL / JPQL查询无效

Hibernate二级缓存偏向于强一致性,而查询缓存也不例外。 与刷新一样,只要关联的表空间发生更改,查询缓存就可以使其条目无效。 每次我们持久/删除/更新实体时 ,使用该特定表的所有查询缓存条目都将失效。

doInTransaction(session -> {Author author = (Author) session.get(Author.class, 1L);assertEquals(1, getLatestPosts(session).size());LOGGER.info("Insert a new Post");Post newPost = new Post("Hibernate Book", author);session.persist(newPost);session.flush();LOGGER.info("Query cache is invalidated");assertEquals(2, getLatestPosts(session).size());
});doInTransaction(session -> {LOGGER.info("Check Query cache");assertEquals(2, getLatestPosts(session).size());
});

该测试将添加一个新的Post ,然后重新运行可缓存的查询。 运行此测试将给出以下输出:

QueryCacheTest - Insert a new Postinsert
intoPost(id, author_id, created_on, name)
values(default, 1, '2015-06-06 17:29:59.909', 'Hibernate Book')UpdateTimestampsCache - Pre-invalidating space [Post], timestamp: 5872029941395456
EhcacheGeneralDataRegion - key: Post value: 5872029941395456QueryCacheTest - Query cache is invalidated
StandardQueryCache - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2StandardQueryCache - Checking query spaces are up-to-date: [Post]
EhcacheGeneralDataRegion - key: Post
UpdateTimestampsCache - [Post] last update timestamp: 5872029941395456, result set timestamp: 5872029695619072
StandardQueryCache - Cached query results were not up-to-dateselectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_
fromPost querycache0_
order byquerycache0_.created_on desc limit 10StandardQueryCache - Caching query results in region: org.hibernate.cache.internal.StandardQueryCache; timestamp=5872029695668224
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
value: [5872029695668224, 2, 1]JdbcTransaction - committed JDBC ConnectionUpdateTimestampsCache - Invalidating space [Post], timestamp: 5872029695680512
EhcacheGeneralDataRegion - key: Post value: 5872029695680512------------------------------------------------------------QueryCacheTest - Check Query cacheStandardQueryCache - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2StandardQueryCache - Checking query spaces are up-to-date: [Post]
EhcacheGeneralDataRegion - key: Post
UpdateTimestampsCache - [Post] last update timestamp: 5872029695680512, result set timestamp: 5872029695668224
StandardQueryCache - Cached query results were not up-to-dateselectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_
fromPost querycache0_
order byquerycache0_.created_on desc limit 10StandardQueryCache - Caching query results in region: org.hibernate.cache.internal.StandardQueryCache; timestamp=5872029695705088
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
value: [5872029695705088, 2, 1]JdbcTransaction - committed JDBC Connection
  • 一旦Hibernate检测到Entity状态转换 ,它将使受影响的查询缓存区域预先失效
  • 不会删除查询缓存条目,但会更新其关联的时间戳
  • 查询缓存始终检查条目键时间戳,如果键时间戳比结果集加载时间戳新,它将跳过读取其值。
  • 如果当前会话重新运行此查询,则结果将再次被缓存
  • 当前数据库事务的提交和更改从会话级隔离传播到常规读取一致性
  • 发生实际的无效,并且缓存条目时间戳再次更新

这种方法可能会破坏READ COMMITTED一致性保证,因为可能进行脏读 ,因为在提交数据库事务之前,当前隔离的更改会传播到Cache。

本机查询无效

正如我前面提到 ,本机查询休眠留在黑暗中,因为它可以不知道本地查询最终可能会修改其表。 在以下测试中,我们将更新Author表,同时检查它对当前Post Query Cache的影响:

doInTransaction(session -> {assertEquals(1, getLatestPosts(session).size());LOGGER.info("Execute native query");assertEquals(1, session.createSQLQuery("update Author set name = '\"'||name||'\"' ").executeUpdate());LOGGER.info("Check query cache is invalidated");assertEquals(1, getLatestPosts(session).size());
});

测试生成以下输出:

QueryCacheTest - Execute native queryUpdateTimestampsCache - Pre-invalidating space [Author], timestamp: 5872035446091776
EhcacheGeneralDataRegion - key: Author value: 5872035446091776
UpdateTimestampsCache - Pre-invalidating space [Post], timestamp: 5872035446091776
EhcacheGeneralDataRegion - key: Post value: 5872035446091776updateAuthor
setname = '"'||name||'"'QueryCacheTest - Check query cache is invalidatedStandardQueryCache - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2StandardQueryCache - Checking query spaces are up-to-date: [Post]
EhcacheGeneralDataRegion - key: Post
UpdateTimestampsCache - [Post] last update timestamp: 5872035446091776, result set timestamp: 5872035200290816
StandardQueryCache - Cached query results were not up-to-dateselectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_
fromPost querycache0_
order byquerycache0_.created_on desc limit 10StandardQueryCache - Caching query results in region: org.hibernate.cache.internal.StandardQueryCache; timestamp=5872035200364544
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
value: [5872035200364544, 1]JdbcTransaction - committed JDBC ConnectionUpdateTimestampsCache - Invalidating space [Post], timestamp: 5872035200372736
EhcacheGeneralDataRegion - key: Post value: 5872035200372736
UpdateTimestampsCache - Invalidating space [Author], timestamp: 5872035200372736
EhcacheGeneralDataRegion - key: Author value: 5872035200372736

即使仅修改了Author表, AuthorPost缓存区域也都无效。 为了解决这个问题,我们需要让Hibernate知道我们要更改哪些表。

本机查询缓存区域同步

Hibernate允许我们通过查询同步提示来定义查询表空间。 提供此信息时,Hibernate可使请求的缓存区域无效:

doInTransaction(session -> {assertEquals(1, getLatestPosts(session).size());LOGGER.info("Execute native query with synchronization");assertEquals(1, session.createSQLQuery("update Author set name = '\"'||name||'\"' ").addSynchronizedEntityClass(Author.class).executeUpdate());LOGGER.info("Check query cache is not invalidated");assertEquals(1, getLatestPosts(session).size());
});

正在生成以下输出:

QueryCacheTest - Execute native query with synchronizationUpdateTimestampsCache - Pre-invalidating space [Author], timestamp: 5872036893995008
EhcacheGeneralDataRegion - key: Author value: 5872036893995008updateAuthor
setname = '"'||name||'"'QueryCacheTest - Check query cache is not invalidatedStandardQueryCache - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
EhcacheGeneralDataRegion -
key: sql: selectquerycache0_.id as id1_1_,querycache0_.author_id as author_i4_1_,querycache0_.created_on as created_2_1_,querycache0_.name as name3_1_ fromPost querycache0_ order byquerycache0_.created_on desc;parameters: ; named parameters: {}; max rows: 10; transformer: org.hibernate.transform.CacheableResultTransformer@110f2StandardQueryCache - Checking query spaces are up-to-date: [Post]
EhcacheGeneralDataRegion - key: Post
UpdateTimestampsCache - [Post] last update timestamp: 5872036648169472, result set timestamp: 5872036648226816
StandardQueryCache - Returning cached query resultsJdbcTransaction - committed JDBC ConnectionUpdateTimestampsCache - Invalidating space [Author], timestamp: 5872036648263680
EhcacheGeneralDataRegion - key: Author value: 5872036648263680

只有提供的表空间无效,离开了邮政查询缓存不变。 可以将本机查询和查询缓存混合在一起,但是需要一些努力。

结论

查询缓存可以提高频繁执行的实体查询的应用程序性能,但这不是免费的。 它容易受到一致性问题的影响,并且如果没有适当的内存管理控制机制,它很容易变得很大。

代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/06/how-does-hibernate-query-cache-work.html

Hibernate查询缓存如何工作相关推荐

  1. hibernate查询缓存_Hibernate查询缓存如何工作

    hibernate查询缓存 介绍 现在,我已经介绍了实体和集合缓存,现在该研究查询缓存的工作原理了. 查询缓存与实体严格相关,它在搜索条件和满足该特定查询过滤器的实体之间绘制关联. 像其他Hibern ...

  2. Hibernate查询缓存全面分析

    http://blog.csdn.net/security08/article/details/5670980 这里介绍Hibernate查询缓存对Iterator不起作用,只对List起作用. 缓存 ...

  3. Hibernate查询缓存

    缓存分类: ◆一级缓存Session级 ◆二级缓存SessionFactory级别 JVM级别 Hibernate查询缓存不固定(根据生命周期 来说 不固定) 生命周期: ◆一级缓存 是和 sessi ...

  4. hibernate查询缓存_在Hibernate中启用实体和查询缓存

    hibernate查询缓存 1.简介 在我执行过的与性能相关的任务中,这就是其中之一. 令人担心的是,如果对于特定实体每次都调用相同的查询,并且表数据在特定的时隙内不易更改,则我们可以使用Hibern ...

  5. Hibernate二级/查询缓存的陷阱

    这篇文章将介绍如何设置Hibernate二级和查询缓存,它们如何工作以及最常见的陷阱. 休眠二级缓存是用于存储实体数据的应用程序级缓存. 查询缓存是一个单独的缓存,仅存储查询结果. 这两个缓存实际上是 ...

  6. Hibernate查询性能优化技巧

    数据库查询性能的提升也是涉及到开发中的各个阶段,在开发中选用正确的查询方法无疑是最基础也最简单的. SQL语句的优化 使用正确的SQL语句可以在很大程度上提高系统的查询性能.获得同样数据而采用不同方式 ...

  7. Hibernate 所有缓存机制详解

    hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和 ...

  8. 清空缓存的命令_超详细的mysql数据库查询缓存原理解析、涉及命令、流程分析等...

    概述 mysql查询缓存在数据库优化可以起到很大的作用,今天主要针对这一块做一个总结,下面一起来看看吧~ 一.缓存条件,原理 MySQL Query Cache是用来缓存我们所执行的SELECT语句以 ...

  9. mysql 缓存优缺点_MySQL查询缓存的优缺点

    任职DBA一年多了,更正下博客. 其实MySQL8.0已经取消了查询缓存.如果是小型项目,又不想用Reids或者MC等缓存,查询结果相对固定,可以在MySQL5.7以下版本设置缓存. ######## ...

最新文章

  1. 探寻阿里云服务器迈入2.0时代的技术要点
  2. LeetCode面试题03. 数组中重复的数字
  3. python中自动化办公 【笔记】
  4. 惠普打印机136w硒鼓芯片怎么清零_关于惠普彩激升级后无法识别硒鼓的处理方案...
  5. MySQL备份和还原数据库及慢查询日志使用
  6. LeetCode#20 有效的括号
  7. 欺骗的艺术——第一部分
  8. win10多合一原版系统_win10多合一系统制作方法详解
  9. 宏病毒实验讲解(含共享文件夹建立)
  10. 从零开始学凸优化理论与KKT条件
  11. [激光原理与应用-19]:《激光原理与技术》-5- 激光器的增益、损耗、自激振荡条件
  12. 【PC工具】微信语音转mp3保存备份方法及工具,微信语音备份方法,silk转mp3工具...
  13. 计算机基础作业1,学习平台-北京大学16春计算机基础与应用作业1答案-成人高等教育_成人本科教育报名_远程网络教育学院-江苏学历网报名服务中心...
  14. 内置式永磁电机maxwell2d_「仿真」永磁同步电机仿真(实操三)Maxwell 2D 静态磁场仿真...
  15. Android常用官网,开发者社区,论坛
  16. non-resource variables are not supported in the long term 无法解决
  17. NTP 网络时间协议
  18. linux shell awk 语法
  19. Android自定义view摇杆,Android 自定义摇杆控件(使用图片)
  20. 电子科技大学2021计算机考研复试科目,2021电子科技大学考研大纲参考书目

热门文章

  1. Android增加自定义监听事件
  2. 在实际使用中 mysql所支持的触发器有_2016计算机二级MySQL冲刺题及答案
  3. vpn mysql_MYSQL数据库
  4. apache.camel_Apache Camel 3.1 –即将推出更多骆驼核心优化
  5. netflix测试能不能看_Netflix监管者测试–引入知事,准官员
  6. idea测试单元错误_不要单元测试错误
  7. undertow ssl_SSL与WildFly 8和Undertow
  8. 将Visual Studio Code设置为jshell中的默认编辑器
  9. Spring Boot删除嵌入式Tomcat服务器,启用Jetty服务器
  10. 迁移学习 简而言之_简而言之Java.io:22个案例研究