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> {
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章