hibernate查询缓存_Hibernate查询缓存如何工作
hibernate查詢緩存
介紹
現(xiàn)在,我已經(jīng)介紹了實(shí)體和集合緩存,現(xiàn)在該研究查詢緩存的工作原理了。
查詢緩存與實(shí)體嚴(yán)格相關(guān),它在搜索條件和滿足該特定查詢過濾器的實(shí)體之間繪制關(guān)聯(lián)。 像其他Hibernate功能一樣,查詢緩存也不像人們想象的那么瑣碎。
實(shí)體模型
對(duì)于我們的測(cè)試用例,我們將使用以下域模型:
Post實(shí)體與Author 具有多對(duì)一關(guān)聯(lián),并且兩個(gè)實(shí)體都存儲(chǔ)在第二級(jí)緩存中。
啟用查詢緩存
默認(rèn)情況下,查詢緩存處于禁用狀態(tài),要激活它,我們需要提供以下Hibernate屬性:
properties.put("hibernate.cache.use_query_cache", Boolean.TRUE.toString());為了使Hibernate緩存給定的查詢結(jié)果,我們需要在創(chuàng)建Query時(shí)顯式設(shè)置cachable查詢屬性 。
直讀緩存
查詢緩存是只讀的 ,就像NONSTRICT_READ_WRITE并發(fā)策略一樣 ,它只能使過時(shí)的條目無效。
在下一個(gè)示例中,我們將緩存以下查詢:
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(); }首先,我們將使用以下測(cè)試案例來研究查詢緩存的內(nèi)部結(jié)構(gòu):
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()); });該測(cè)試生成以下輸出:
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- 清除所有緩存區(qū)域,以確保緩存為空
- 運(yùn)行后查詢后,查詢緩存將檢查以前存儲(chǔ)的結(jié)果
- 因?yàn)闆]有緩存條目,所以查詢轉(zhuǎn)到數(shù)據(jù)庫(kù)
- 所選實(shí)體和查詢結(jié)果均被緩存
- 然后,我們驗(yàn)證Post實(shí)體是否存儲(chǔ)在二級(jí)緩存中
- 后續(xù)查詢請(qǐng)求將從緩存中解決,而無需訪問數(shù)據(jù)庫(kù)
查詢參數(shù)
查詢參數(shù)嵌入在緩存條目鍵中,如以下示例所示。
基本類型
首先,我們將使用基本的類型過濾:
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]該參數(shù)存儲(chǔ)在高速緩存條目鍵中。 緩存條目值的第一個(gè)元素始終是結(jié)果集的獲取時(shí)間戳。 以下元素是此查詢返回的實(shí)體標(biāo)識(shí)符。
實(shí)體類型
我們還可以使用實(shí)體類型作為查詢參數(shù):
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()); });緩存條目與我們之前的示例相似,因?yàn)镠ibernate僅將實(shí)體標(biāo)識(shí)符存儲(chǔ)在緩存條目鍵中。 這很有意義,因?yàn)镠ibernate已經(jīng)緩存了Author實(shí)體。
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二級(jí)緩存偏向于強(qiáng)一致性,而查詢緩存也不例外。 與刷新一樣,只要關(guān)聯(lián)的表空間發(fā)生更改,查詢緩存就可以使其條目無效。 每次我們持久/刪除/更新實(shí)體時(shí) ,使用該特定表的所有查詢緩存條目都將失效。
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()); });該測(cè)試將添加一個(gè)新的Post ,然后重新運(yùn)行可緩存的查詢。 運(yùn)行此測(cè)試將給出以下輸出:
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檢測(cè)到Entity狀態(tài)轉(zhuǎn)換 ,它就會(huì)使受影響的查詢緩存區(qū)域預(yù)先失效
- 不會(huì)刪除查詢緩存條目,但會(huì)更新其關(guān)聯(lián)的時(shí)間戳
- 查詢緩存始終檢查條目鍵時(shí)間戳,如果鍵時(shí)間戳比結(jié)果集加載時(shí)間戳新,則它會(huì)跳過讀取其值。
- 如果當(dāng)前會(huì)話重新運(yùn)行此查詢,則結(jié)果將再次被緩存
- 當(dāng)前數(shù)據(jù)庫(kù)事務(wù)的提交和更改從會(huì)話級(jí)隔離傳播到常規(guī)讀取一致性
- 發(fā)生實(shí)際的無效,并且緩存條目時(shí)間戳再次被更新
這種方法可能破壞READ COMMITTED一致性保證,因?yàn)榭赡苓M(jìn)行臟讀 ,因?yàn)樵谔峤粩?shù)據(jù)庫(kù)事務(wù)之前,當(dāng)前隔離的更改會(huì)傳播到Cache。
本機(jī)查詢無效
正如我前面提到 ,本機(jī)查詢Hibernate留在黑暗中,因?yàn)樗梢圆恢辣镜夭樵冏罱K可能會(huì)修改其表。 在以下測(cè)試中,我們將更新Author表,同時(shí)檢查它對(duì)當(dāng)前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()); });測(cè)試生成以下輸出:
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表, Author和Post緩存區(qū)域也都無效。 為了解決這個(gè)問題,我們需要讓Hibernate知道我們要更改哪些表。
本機(jī)查詢緩存區(qū)域同步
Hibernate允許我們通過查詢同步提示來定義查詢表空間。 提供此信息時(shí),Hibernate可以使請(qǐng)求的緩存區(qū)域無效:
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只有提供的表空間無效,離開了郵政查詢緩存不變。 可以將本機(jī)查詢和查詢緩存混合使用,但是需要一些努力。
結(jié)論
查詢緩存可以提高頻繁執(zhí)行的實(shí)體查詢的應(yīng)用程序性能,但這不是免費(fèi)的。 它容易受到一致性問題的影響,并且如果沒有適當(dāng)?shù)膬?nèi)存管理控制機(jī)制,它很容易變得很大。
代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2015/06/how-does-hibernate-query-cache-work.html
hibernate查詢緩存
總結(jié)
以上是生活随笔為你收集整理的hibernate查询缓存_Hibernate查询缓存如何工作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑版邮箱客户端下载(电脑版邮箱客户端下
- 下一篇: hazelcast入门教程_Hazelc