mybatis 二級緩存實踐

參考文檔
https://mybatis.org/mybatis-3/sqlmap-xml.html#cache

xml and java

1、@CacheNamespace(flushInterval = 1800000)
2、<cache flushInterval="1800000">
</cache>
3、二者不能同時配置(否則報錯),想要同時生效。就需要在xml中配置cache 。然後java中配置ref自己

那麼問題來了,如何在一個namespace下配置多個 ache-ref?
我現在是莫得辦法的。。只有暫時規避這種情況

if use mybatis_plus

yml file add

cache-enabled: true

for mapper

@CacheNamespace(
implementation = PerpetualCache.class,
eviction = LruCache.class,
flushInterval = 60 * 60 * 30,
size = 1024,
readWrite = true,
blocking = true)

for statament

add cache
@Options(useCache=true) 默認 開啓單語句緩存
@Options(useCache=false) 關閉單語句緩存

clear cache
@Options(flushCache= Options.FlushCachePolicy.FALSE) 關閉單語句刷新緩存
@Options(flushCache= Options.FlushCachePolicy.true) 單語句總是刷新緩存
@Options(flushCache= Options.FlushCachePolicy.DEFAULT) 默認情況下 select 是false,aud是true

if use join

如何在join查詢中控制cache的維護?
假設在a表中存在一個mapper接口:a join b 查詢生成了cache。
b表被修改了。我想讓這個a表mapper的cache失效,該如何做到?

使用@CacheNamespaceRef註解可以做到

要修改的接口

@CacheNamespaceRef(ProductBrandRepository.class)
@CacheNamespace(
        flushInterval = 30 * 60 * 1000
)
@Mapper
public interface CateBrandRelationShipMapper extends BaseMapper<CateBrandRelationShip> {

查詢的接口

@CacheNamespace(
        flushInterval = 30 * 60 * 1000
)
@Mapper
public interface ProductBrandRepository extends BaseMapper<ProductBrand> {

    @Select("SELECT\n" +
            "   a.id,\n" +
            "   a.brand_no brandNo,\n" +
            "   a.brand_name brandName,\n" +
            "   a.brand_img_url brandImgUrl,\n" +
            "   a.desc,\n" +
            "   GROUP_CONCAT( DISTINCT CONCAT_WS( ' ', b.category_name, b.brand_no ) SEPARATOR '\\n' ) k3CodePrefix \n" +
            "FROM\n" +
            "   product_brand a\n" +
            "   LEFT JOIN cate_brand_relationship b ON a.id = b.brand_id  \n" +
            "   ${ew.customSqlSegment}\n" +
            "GROUP BY\n" +
            "   a.brand_name \n" +
            "ORDER BY\n" +
            "   a.id DESC ")
    @Options
    IPage<ProductBrandDto>
    findByPage(@Param("page") IPage<ProductBrandDto> page, @Param(Constants.WRAPPER) Wrapper<ProductBrandDto> queryWrapper);

  • first,它不能同時使用在a,b之間。否則報錯,只能使用在一個mapper類上
  • CacheNamespaceRef只能使用在mapper類上。只有mapper上的改註解會被掃描到
  • 有@CacheNamespaceRef的一方可以操作清除指定ref的一方緩存
  • 如果存在xml和註解形式並存的情況。我們在xml中配置cache表標籤。接口中使用CacheNamespaceRef可以讓二者兼顧

a 中配置了CacheNamespaceRef,指向b;
含義是 a來操作b的緩存

缺陷

1、對於多表join的cache的維護不太好;

2、最好在【只有單表操作】的表上使用緩存,不只是要保證這個表在整個系統中只有單表操作,而且和該表有關的全部操作必須全部在一個namespace下。必須約束對指定表的crud寫在指定namesapce mapper下。否則會出現數據不一致

3、myabtis 2 level cache 控制粒度比較粗。不能做到像spring cache那樣根據 緩存key 細粒度的控制緩存

best practice 最佳實踐

針對join的情況
1、多對多。中間表。
我們可將所有的join語句放到中間表的mapper中。然後通過ref指定其它兩個的表,mapper。這樣其它表的mapper進行update時會讓join查詢cache失效。以此達到目的

2、1對多。
隨便取一個。然後另一個ref它就行

問題

在只使用註解的情況下可能會出現mapper的掃描加載的順序先後原因導致的報錯。Cache-ref not yet resolved

中間表mapper中,用xml的方式代替註解的cache聲明解決:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gbm.cloud.treasure.dao.CateBrandRelationShipMapper">
    <cache>
    </cache>

</mapper>

接口中要ref自己。否則mapper接口中的實現不能生效

@CacheNamespaceRef(CateBrandRelationShipMapper.class)
@Mapper
public interface CateBrandRelationShipMapper extends BaseMapper<CateBrandRelationShip> {

多對多的一方

@CacheNamespaceRef(CateBrandRelationShipMapper.class)
@Mapper
public interface ProductCategoryRepository extends BaseMapper<ProductCategory> {

多對多的另一方

@CacheNamespaceRef(CateBrandRelationShipMapper.class)
@Mapper
public interface ProductBrandRepository extends BaseMapper<ProductBrand> {
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章