springCache搭配redis替代mybatis二级缓存[954L]

11 篇文章 0 订阅
10 篇文章 0 订阅

mybatis_cache系列

建议按顺序阅读,有一些代码沿用之前的code,与一级缓存完全一致的内容或结果就不再操作了

前言

本文主要阐述springCache的基本使用指南。
上一篇也提到了mybatis二级缓存的弊端,二级缓存作用域有一点是针对xml文件。
假设我们在A.xml缓存了结果集,在B.xml修改了同一条DB数据,则无法影响A.xml中的缓存数据,可能导致缓存与DB数据不一致的问题。

所以本文使用SpringCache替代mybatis的二级缓存,实现缓存数据示例。


springCache介绍

官网入门指南地址:https://spring.io/guides/gs/caching/
springCache实际是一个缓存的抽象,需要我们用具体的实现。比方说用redis。
并且可以在不侵入代码的前提下实现缓存,例如针对某一个函数设置是否缓存。

SpringCache缓存功能的实现是依靠下面的这几个注解完成的。

  • @EnableCaching:开启缓存功能
  • @Cacheable:定义缓存,用于触发缓存
  • @CachePut:定义更新缓存,触发缓存更新
  • @CacheEvict:定义清除缓存,触发缓存清除
  • @Caching:组合定义多种缓存功能
  • @CacheConfig:定义公共设置,位于class之上


Coding

先贴一下demo项目结构

项目代码还是沿用之前mybatis一二级缓存的demo示例,没什么代码量,只是加了一个service还有改成了基于springboot的方式。

SpringCacheApplication

package com.w954l.blog;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching
@SpringBootApplication
@MapperScan("com.w954l.blog.mapper")
public class SpringCacheApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringCacheApplication.class, args);
	}

}

@EnableCaching:开启springCache

application.yml


spring:
  application:
    name: spring-cache
  redis:
      # 选择0号数据库
      database: 0
      # redis服务器 ip
      host: cache.954l.com
      # redis服务器 端口
      port: 6379
      # redis服务器 密码
      password: password
  datasource:
    url: jdbc:mysql:///blog_mybatis_cache?characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: password
    driver-class-name: com.mysql.jdbc.Driver
  cache:
    # 配置springCache的实现为redis
    type: redis
mybatis:
  configuration:
    # 打印执行的sql语句到控制台
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.w954l.blog.mapper

关键性代码都加了注释了,就不额外说明了。


@Cacheable

该注解可添加在函数或类上。
添加在函数上表示这个函数的返回值需要被缓存。
添加在类上表示这个类里所有的函数的返回值都需要被缓存。

添加@Cacheable注解的service执行过程

client service db 第一次查询 查询数据库 数据返回,写入实现springCache的缓存 数据返回 第二次查询 命中缓存,返回数据 client service db

代码示例

UserServiceTest

/**
 * @author 954L
 * @create 2020/6/14 14:36
 */
@SpringBootTest(classes = SpringCacheApplication.class)
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void queryByIdTest(){
        User user = userService.queryById(1);
        System.out.println(user);
    }

}

UserService

/**
 * @author 954L
 * @create 2020/6/14 14:35
 */
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Cacheable(value = "userById")
    public User queryById(Integer id) {
        return userMapper.queryById(id);
    }
}


第一次查询控制台打印内容


第二次查询控制台打印内容

redis_mananger

根据第一次查询控制台的sql可以断定执行了sql,再看第二次查询的控制台打印内容并没有打印sql,由此可以说明第二次应该是命中了缓存,导致没有去数据库查询。
打开redis管理工具中确实是缓存了我们刚刚查询的数据。

@Cacheable(value = “userById”)
value:fieldId
存储在redis中是hash数据结构:fieldId -> key -> value
fieldId:就是我们输入的value值:userById
key:默认是所有参数值组合合成作为key,也可自定义,但必须使用SPEL表达式。
如:@Cacheable(value = “userById”, key = “#id”)
value:需要缓存的值,在这里就是指这个函数的返回值,就是User对象。


@CachePut

用于更新缓存数据,如果本没有缓存,则创建。
更新同一个fieldId跟同key下的value内容

代码示例
UserServiceTest

@Test
public void updateByIdTest(){
    User user = new User();
    user.setId(1);
    user.setName("123");
    user.setPassword("456");
    userService.updateById(user);
    queryByIdTest();
}

UserService

@CachePut(value = "userById", key = "#user.id")
public User updateById(User user) {
    userMapper.updateById(user);
    return user;
}

控制台打印

打印了update语句,却没有打印select,说明select命中了缓存,而打印的User对象中的属性也是更改之后的。


@CacheEvict

删除缓存,常用于删除数据。以及缓存中含有集合数据,修改了其中一条数据时也要添加该注解,否则将出现数据不一致问题。

代码示例
UserServiceTest

@Test
public void deleteByIdTest(){
    userService.deleteById(1);
}

UserService

@CacheEvict(value = "userById")
public void deleteById(Integer id) {
    userMapper.deleteById(id);
}

控制台打印


redis_mananger

sql语句可以看到成功删除了一条数据,而redis中的缓存数据也同步删除了。


@Caching

上述的注解基本可以实现CRUD操作了,最后加一个@Caching吧。
还有其他用法如自定义缓存实现等,以后有空再补上吧。

@Caching主要作用是用于组合多个缓存注解,比方说要把当前返回值数据同时缓存到两个不同的field中。

代码示例
UserServiceTest

@Test
public void queryAllTest(){
    List<User> userList = userService.queryAll();
    userList.stream().forEach(System.out::print);
}

UserService

@Caching(
        cacheable = {
                @Cacheable(value = "userAll"),
                @Cacheable(value = "users")
        },
        put = {
                @CachePut(value = "userList")
        },
        evict = {
                @CacheEvict(value = "user-list")
        }
)
public List<User> queryAll() {
    return userMapper.queryAll();
}

控制台打印


redis_mananger

这里就不解释了吧,就是上述几个注解的组合使用,如果都看到这里了,那肯定能明白啥意思。
good Job!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

954L

帮帮孩子把~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值