【快速学习系列】Mybatis缓存和使用SpringBoot开启MyBatis缓存+ehcache
创始人
2024-02-07 02:58:16

【快速学习系列】Mybatis缓存和使用SpringBoot开启MyBatis缓存+ehcache

Mybatis缓存

MyBatis一级缓存

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库

tips:MyBatis一级缓存是默认开启

示例

写了一个分页查询的功能

测试类

@Test
public void findUserArrays() {SqlSession sqlSession = MyBatisUtil.createSqlSession();UserDao userDao = sqlSession.getMapper(UserDao.class);//测试mybatis一级缓存UserDao userDao1 = sqlSession.getMapper(UserDao.class);List userList = userDao.findUserArrays(new Integer[]{1, 2}, 1);//调用两次方法但实际sql只执行一次(同sqlsession情况下且请求的方法和参数一致)List userList1 = userDao1.findUserArrays(new Integer[]{1, 2}, 1);for (User user : userList) {System.out.println(user.toString());}MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
结果

请添加图片描述

MyBatis二级缓存

MyBatis的二级缓存是**Application级别(也就是同一个SqlSessionFactory)**的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

tips:MyBatis二级缓存是默认不开启

开启二级缓存

SqlSessionFactory层面上的二级缓存默认是不开启的,二级缓存的开席需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置就可以开启缓存

步骤

1、在 MyBatis的配置文件 mybatis-config.xml中加入



2、在mapper.xml中开启二级缓存,mapper.xml下的sql执行完成会存储到它的缓存区




select,insert,update标签中的缓存属性
useCache=false,禁用二级缓存

flushCache=true 刷新缓存 ,一般用于insert,update

tips:这里我们可以看到,当设置二级缓存时,策略是控制整个mapper文件的,其实这样是非常不灵活的,我们更希望能够控制每一个业务方法都能够有不同的缓存策略,这样使用起来也是更符合实际开发的需要,所以下面的就是相对来说更好的一种缓存办法

使用SpringBoot开启MyBatis缓存+ehcache

事实上MyBatis自带的缓存还是有着一定缺陷的,而我们使用第三方的ehcache缓存则会更灵活

步骤

导入jar包

添加maven依赖

pom.xml


org.springframework.bootspring-boot-starter-cache

net.sf.ehcacheehcache

设置ehcache.xml配置

在项目的resources下新建一个名为ehcache.xml的配置文件,

然后把下面的代码粘过去即可




上面标签可能会爆红,那个先不用管也没问题

使用@EnableCaching注解在启动类上开启缓存

@SpringBootApplication
@EnableCaching  //开启缓存
public class XXXXApplication {public static void main(String[] args) {SpringApplication.run(XXXXApplication.class, args);}}

配置yml文件中缓存设置

首先需要开启MyBatis的二级缓存

# mybatis相关配置
mybatis:mapper-locations: classpath:mappers/*.xmltype-aliases-package: com.r.springboot1.pojo    # xml映射文件中实体类起别名configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 在控制台打印日志信息cache-enabled: true  # 开启MyBatis的二级缓存

然后在配置中来读取我们刚刚写的缓存文件ehcache.xml

spring:cache:ehcache:config: classpath:ehcache.xml # 读取ehcache.xml缓存策略文件

Spring Cache注解使用

因为我们是使用注解来实现缓存,所以像原来在dao层映射文件中来配置缓存是没必要的,所以我们需要在Service的实现层来写缓存注解(注解可以是类上也可以是方法上)

@Cacheable

tips:如果使用时只写注解而不指定是哪个缓存策略的话,@Cacheable会自动执行默认策略😅

可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。

@Cacheable可以指定三个属性,value、key(使用key是为了让缓存数据之间能够有所区分,这样不会使其混乱)和condition (过滤条件)

不同配置方法示例
@Cacheable("myCache1")	//Cache是发生在ehcache.xml中myCache1上的
public User find(Integer id) {....
}
@Cacheable({"cache1", "cache2"})	//Cache是发生在ehcache.xml中cache1和cache2上的(可以同时设置多个)
public User find(Integer id) {.....
}
//自定义策略是指我们可以通过Spring的EL表达式来指定我们的key
//#id指参数id作为key(按id区分同一个缓存策略中的不同缓存信息,使用唯一的id则不会使缓存混到一起出现问题)
@Cacheable(value="myCache1", key="#id")
public User find(Integer id) {...
}
//#p0标识第一个参数作为key(p相当于param,#p0、#p1、#p2...依次代表第一个、第二个和第三个参数,以此类推)
@Cacheable(value="myCache1", key="#p0")
public User find(Integer id) {.....
}
//#user.user_id表示对象user属性user_id作为key(可以用对象的属性作为key用来区分,当然id还是唯一的字段,使用起来不会使缓存混乱)
@Cacheable(value="myCache1", key="#user.user_id")
public User find(User user) {.....
}
//也可以混着这样用
@Cacheable(value="myCache1", key="#p0.user_id")
public User find(User user) {.....
}
Spring还为我们提供了一个root对象可以用来生成key
示例描述
root.methodName当前方法名
root.method.name当前方法
root.target当前被调用的对象
root.targetClass当前被调用的对象的class
root.args[0]当前方法参数组成的数组
root.caches[0].name当前被调用的方法使用的Cache

condition使用

//表示只有当user的id为偶数时才会进行缓存   
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")   
public User find(User user) {    ...   }
使用key的情景

key不是什么时候都适合使用

当要显示一些共享的缓存信息时,没有必要使用key(key适用于将缓存信息独立分离开进行缓存的情况)

在一些未知且经常变化的参数上,没有必要使用key(key适用于缓存一些有限的、且唯一的参数字段上,就比如id)

注意事项

使用的方法实体类必须经过序列化,否则会报错

请添加图片描述

报错显示所用的实体类为进行序列化,但同时也证明缓存的确是在运行着

给实体类序列化示例

implements Serializable即可

public class Provider implements Serializable {}

然后运行自己的方法后我们可以在控制台看到,虽然多次请求,但因为我们设置了缓存,会发现sql语句只运行了一次,这也说明我们的缓存设置成功

请添加图片描述

@CachePut

使用@CachePut时我们可以指定的属性跟@Cacheable是一样的

@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中

也就是说@Cacheable每次执行前都会先看一下之前是否有缓存,如果有就用原来存在的缓存,而@CachePut每次执行都直接刷新缓存,不会看之前是否存在缓存

@CacheEvict

清除缓存, 可以指定的属性有value、key、condition、allEntries、beforeInvocation

tips:一般用于增删改上,因为我们定义的缓存策略中可能存在当我们增删改时还没有过缓存时间,所以这时候就会显示还没有改的样子,所以我们为了能够改变后即刻刷新缓存,所以需要用到这个

使用示例
@CacheEvict(value="myCache",key="#p0.user_id")
public int updUser(SfUser user) throws Exception {return sfUserMapper.updUser(user);
}
//allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率(false时指执行方法时,我只清除对应id方法的这一条,true是执行方法时,所有的缓存都清掉,当再次执行有@Cacheable的方法时缓存再被再次加入)@CacheEvict(value="users", allEntries=true)public void delete(Integer id) {System.out.println("delete user by id: " + id);
}

tips:如果使用@CacheEvict的时候不设置key,那么它会清除掉当前所有的缓存(当然清楚的是你设置的当前方法中配置的相应缓存策略,并不是说所有的完完全全的缓存全清除了😁)

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...