草庐IT

mybatis 二级缓存实践

尹楷楷 2023-03-28 原文

参考文档
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> {

有关mybatis 二级缓存实践的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - 如何在 Ubuntu 中清除 Ruby Phusion Passenger 的缓存? - 2

    我试过重新启动apache,缓存的页面仍然出现,所以一定有一个文件夹在某个地方。我没有“公共(public)/缓存”,那么我还应该查看哪些其他地方?是否有一个URL标志也可以触发此效果? 最佳答案 您需要触摸一个文件才能清除phusion,例如:touch/webapps/mycook/tmp/restart.txt参见docs 关于ruby-如何在Ubuntu中清除RubyPhusionPassenger的缓存?,我们在StackOverflow上找到一个类似的问题:

  3. ruby-on-rails - Ruby on Rails 计数器缓存错误 - 2

    尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot

  4. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  5. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

    我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

  6. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  7. Ruby 最佳实践 : working with classes - 2

    参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin

  8. ruby-on-rails - 使用 Rails 事件记录获取二级模型 - 2

    我有一个帖子属于城市的关系,城市又属于一个州,例如:classPost现在我想找到所有帖子及其所属的城市和州。我编写了以下查询来获取带有城市的帖子,但不知道如何在同一查找器中获取带有城市的相应州:@post=Post.find:all,:include=>[:city]感谢任何帮助。谢谢。 最佳答案 Post.all(:include=>{:city=>:state}) 关于ruby-on-rails-使用Rails事件记录获取二级模型,我们在StackOverflow上找到一个类似的问

  9. ruby - 存储外部 API 的密码 - 最佳实践 - 2

    如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。

  10. ruby-on-rails - bundle 安装尝试使用缓存文件 - 2

    当我尝试进行bundle安装时,我的gem_path和gem_home指向/usr/local/rvm/gems/我没有写入权限,并且由于权限无效而失败。因此,我已将两个路径都更改为我具有写入权限的本地目录。这样做时,我进行了bundle安装,我得到:bruno@test6:~$bundleinstallFetchinggemmetadatafromhttps://rubygems.org/.........Fetchinggemmetadatafromhttps://rubygems.org/..Bundler::GemspecError:Couldnotreadgemat/afs/

随机推荐