Mybatis Cache(一)MybatisCache+Redis

前面提到了,使用mybatis cache,一般是结合redis使用。

一、demo

1、数据表
create table demo.t_address
(
    id           int auto_increment
        primary key,
    address_name varchar(200) null,
    address_code varchar(20)  null,
    address_type int          null
);

项目结构:

2、pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>plus-mybatis-cache</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/>
    </parent>


    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--尽量不要同时导入mybatis 和 mybatis_plus,避免版本差异-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
    </dependencies>
</project>
3、配置文件
server.port=1112
server.servlet.context-path=/mybatisCacheDemo
#mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3308/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=wtyy
#mybatis
mybatis.mapper-locations=classpath*:mapper/*Mapper.xml
#打印日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 开启二级缓存
mybatis-plus.configuration.cache-enabled=true
#redis
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.password=
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.time-between-eviction-runs=30s
4、util
package com.pluscache.demo.util;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.util.Map;

@Component
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext ;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    public static Object getBean(String name) {
        return ApplicationContextUtil.applicationContext.getBean(name);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
        return applicationContext.getBeansOfType(clazz);
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static <T extends Annotation> T getAnnotation(Object bean, Class<T> annotationClass) {
        T annotation = bean.getClass().getAnnotation(annotationClass);
        if (annotation == null) {
            annotation = AopUtils.getTargetClass(bean).getAnnotation(annotationClass);
        }
        return annotation;
    }

}
5、config
package com.pluscache.demo.config;

import com.pluscache.demo.util.ApplicationContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

@Slf4j
//@Component
public class MybatisRedisCache implements Cache {

    /* * id是必须的带上的,这里的id会指定当前放入缓存的mapper的namespace
    * 如这里的id就是com.sample.dao.IEmployeeDao
    */
    private final String id;
    private  RedisTemplate redisTemplate;

    public MybatisRedisCache(final String id) {
       //获取redis实例
        //redisTemplate = (RedisTemplate) ApplicationContextUtil.getBean("redisTemplate");
        //指定key的序列化方式
        //redisTemplate.setKeySerializer(new StringRedisSerializer());
        //redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        this.id = id;
    }
    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object key, Object value) {
        this.getRedisTemplate();
        redisTemplate.opsForHash().put(id.toString(),key.toString(),value);
    }

    private void getRedisTemplate() {
        if (redisTemplate == null) {
            //由于启动期间注入失败,只能运行期间注入,这段代码可以删除
            redisTemplate = (RedisTemplate) ApplicationContextUtil.getBean("redisTemplate");
        }
    }

    @Override
    public Object getObject(Object key) {
        this.getRedisTemplate();
        return redisTemplate.opsForHash().get(id.toString(),key.toString());
    }

    @Override
    public Object removeObject(Object key) {
        return null;
    }

    @Override
    public void clear() {
        this.getRedisTemplate();
        redisTemplate.delete(id.toString());
    }

    @Override
    public int getSize() {
        this.getRedisTemplate();
        return redisTemplate.opsForHash().size(id.toString()).intValue();
    }
}
6、dto
package com.pluscache.demo.dto;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName("t_address")
public class AddressDTO implements Serializable {
    private Integer id;
    private String addressName;
    private String addressCode;
    public Integer addressType;
}
7、dao
(1)repository

   可以省略,移到service中

package com.pluscache.demo.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.pluscache.demo.dto.AddressDTO;
import com.pluscache.demo.mapper.AddressMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@Slf4j
public class AddressRepository {

    @Autowired
    private AddressMapper addressMapper;

    //plus新增
    public void insert(AddressDTO addressDTO) {
        addressMapper.insert(addressDTO);
    }

    //手动SQL新增
    public void save(AddressDTO addressDTO) {
        addressMapper.save(addressDTO);
    }

    public AddressDTO getById(Integer id) {
        LambdaQueryWrapper<AddressDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AddressDTO::getId, id);
        return addressMapper.selectOne(queryWrapper);
    }

    public List<AddressDTO> listByType(Integer type) {
        LambdaQueryWrapper<AddressDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AddressDTO::getAddressType, type);
        return addressMapper.selectList(queryWrapper);
    }

    public List<AddressDTO> listByTypeRecord(Integer type) {
        return addressMapper.listByTypeRecord(type);
    }

    public List<AddressDTO> listById(Integer id) {
        LambdaQueryWrapper<AddressDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AddressDTO::getId, id);
        return addressMapper.selectList(queryWrapper);
    }
}
(2)mapper

   在这里做的缓存

package com.pluscache.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pluscache.demo.config.MybatisRedisCache;
import com.pluscache.demo.dto.AddressDTO;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@CacheNamespace(implementation = MybatisRedisCache.class, eviction = MybatisRedisCache.class)
public interface AddressMapper extends BaseMapper<AddressDTO> {

    void save(@Param("record") AddressDTO addressDTO);

    List<AddressDTO> listByTypeRecord(@Param("type") Integer type);
}
(3)xml
<?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.pluscache.demo.mapper.AddressMapper">

    <cache-ref namespace="com.pluscache.demo.mapper.AddressMapper"/>

    <insert id="save">
        insert into t_address(address_name,
                              address_code,
                              address_type
                              ) values (#{record.addressName},
                                        #{record.addressCode},
                                        #{record.addressType})
    </insert>

    <select id="listByTypeRecord" resultType="com.pluscache.demo.dto.AddressDTO">
        select address_name,address_code from t_address where address_type =#{type}
    </select>

</mapper>
8、service
package com.pluscache.demo.service.impl;

import com.pluscache.demo.dto.AddressDTO;
import com.pluscache.demo.repository.AddressRepository;
import com.pluscache.demo.service.AddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("addressService")
public class AddressServiceImpl implements AddressService {

    @Autowired
    private AddressRepository addressRepository;

    @Override
    public void insert(AddressDTO addressDTO) {
        addressRepository.insert(addressDTO);
    }

    @Override
    public void save(AddressDTO addressDTO) {
        addressRepository.save(addressDTO);
    }

    @Override
    public AddressDTO getById(Integer id) {
        return addressRepository.getById(id);
    }

    @Override
    public List<AddressDTO> listByType(Integer type) {
        return addressRepository.listByType(type);
    }

    @Override
    public List<AddressDTO> listByTypeRecord(Integer type) {
        return addressRepository.listByTypeRecord(type);
    }

    @Override
    public List<AddressDTO> listById(Integer id) {
        return addressRepository.listById(id);
    }
}
9、controller
package com.pluscache.demo.controller;

import com.pluscache.demo.dto.AddressDTO;
import com.pluscache.demo.service.AddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/address")
public class AddressController {

    @Autowired
    private AddressService addressService;

    @RequestMapping("/insert")
    public void insert(AddressDTO addressDTO) {
        addressService.insert(addressDTO);
    }

    @RequestMapping("/save")
    public void save(AddressDTO addressDTO) {
        addressService.save(addressDTO);
    }

    @RequestMapping("/getById")
    public AddressDTO getById(Integer id) {
        return addressService.getById(id);
    }


    @RequestMapping("/listByType")
    public List<AddressDTO> listByType(Integer type) {
        return addressService.listByType(type);
    }

    @RequestMapping("/listByTypeRecord")
    public List<AddressDTO> listByTypeRecord(Integer type) {
        return addressService.listByTypeRecord(type);
    }


    @RequestMapping("/listById")
    public List<AddressDTO> listById(Integer id) {
        return addressService.listById(id);
    }

}
10、启动类
package com.pluscache.demo;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.pluscache.demo.mapper")
@SpringBootApplication
public class MybatisPlusApplication {

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

    }
}
11、测试 
(1)新增数据

    新增了几条数据

(2)SQL法根据type查询

① 第一次访问

localhost:1112/mybatisCacheDemo/address/listByTypeRecord?type=1

后台打印:

查看redis生成了缓存

 ② 再次访问,没有查询db了

(3) mybatis-plus根据type查询

  ①  第一次访问localhost:1112/mybatisCacheDemo/address/listByType?type=1

后台从db查询

查看redis的缓存:可以看到又生成了一条缓存

②  再次访问,没有从数据库查询

 (4)mybatis-plus根据id查询

①  第一次访问localhost:1112/mybatisCacheDemo/address/listById?id=1

走db查看

查看redis缓存:

 ②  再次访问,不再走db查询

 (5)执行add

这里生成的id是自增长的,理论上,只需要清空type=1的缓存,不需要清空id=1的缓存。但是刷新redis可以看到,整个大key都清除了。

二、缺点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/640521.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

6.小程序页面布局 - 账单明细

文章目录 1. 6.小程序页面布局 - 账单明细1.1. 竞品1.2. 布局分析1.3. 布局demo1.4. 页面实现-头部1.5. 账单明细1.5.1. 账单明细-竞品分析1.5.2. 账单明细-实现1.5.2.1. 账单明细-实现-mock数据1.5.2.2. 每日收支数据的聚合整理1.5.2.3. 页面scroll-view 1.6. TODO 1. 6.小程序…

雷电预警监控系统:守护安全的重要防线

TH-LD1在自然界中&#xff0c;雷电是一种常见而强大的自然现象。它既有震撼人心的壮观景象&#xff0c;又潜藏着巨大的安全风险。为了有效应对雷电带来的威胁&#xff0c;雷电预警监控系统应运而生&#xff0c;成为现代社会中不可或缺的安全防护工具。 雷电预警监控系统的基本…

Convolutional Occupancy Networks【ECCV2020】

论文&#xff1a;https://arxiv.org/pdf/2003.04618 代码&#xff1a;GitHub - autonomousvision/convolutional_occupancy_networks: [ECCV20] Convolutional Occupancy Networks 图 1&#xff1a;卷积占据网络。传统的隐式模型 (a) 由于其全连接网络结构&#xff0c;表现能力…

政策及需求多因素驱动下 中国适老化改造市场空间大

政策及需求多因素驱动下 中国适老化改造市场空间大 适老化改造是为了提高老年人居住环境的舒适度和安全性&#xff0c;满足老年人居住需求进行的建筑改造&#xff0c;根据住房和城乡建设部城市建设司发布的《城市居家适老化改造指导手册》可以将适老化改造分为基础性改造和提升…

Spring Cloud 系列之Gateway:(9)初识网关

传送门 Spring Cloud Alibaba系列之nacos&#xff1a;(1)安装 Spring Cloud Alibaba系列之nacos&#xff1a;(2)单机模式支持mysql Spring Cloud Alibaba系列之nacos&#xff1a;(3)服务注册发现 Spring Cloud 系列之OpenFeign&#xff1a;(4)集成OpenFeign Spring Cloud …

【小笔记】如何在docker中更新或导入neo4j数据?

如何在docker中更新或导入neo4j数据&#xff1f; &#xff08;1&#xff09;背景&#xff1a; 我尝试了4.4.9和5.19.0版本的Neo4j社区版&#xff0c;基于他们的镜像创建容器后&#xff0c;需要导入我准备好的csv文件或dump文件&#xff0c;因为数据量非常大&#xff0c;所以采…

装备制造项目管理软件:奥博思PowerProject项目管理系统

数字化正逐步改变着制造方式和企业组织模式。某制造企业领导层透露&#xff0c;在采用数字化项目管理模式后&#xff0c;企业的发展韧性更加强劲&#xff0c;构筑起了竞争新优势&#xff0c;企业产品研制周期缩短25%&#xff0c;生产效率提升18%。 随着全球经济的发展&#xf…

北理工提出 LTrack 双摄像头系统 | 专注于暗场景多目标跟踪,自动驾驶和夜间监控的福音!

低光照场景在现实世界应用中很普遍&#xff08;例如自动驾驶和夜间监控&#xff09;。最近&#xff0c;在各种实际用例中的多目标跟踪受到了很多关注&#xff0c;但在暗场景中的多目标跟踪却鲜少被考虑。 在本文中&#xff0c;作者专注于暗场景中的多目标跟踪。为了解决数据集…

【电子学会】2023年09月图形化一级 -- 芝麻开门

芝麻开门 1. 准备工作 &#xff08;1&#xff09;删除小猫角色&#xff0c;添加角色Key&#xff1b; &#xff08;2&#xff09;删除白色背景&#xff0c;添加背景Castle 1和Pathway。 2. 功能实现 &#xff08;1&#xff09;点击绿旗&#xff0c;钥匙在舞台中间&#xff…

Git 的安装和使用

一、Git 的下载和安装 目录 一、Git 的下载和安装 1. git 的下载 2. 安装 二、Git 的基本使用-操作本地仓库 1 初始化仓库 1&#xff09;创建一个空目录 2&#xff09;git init 2 把文件添加到版本库 1&#xff09;创建文件 2&#xff09;git add . 3&#xff09;g…

51单片机简单控制180度舵机

代码&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1K9dg2NwRhy49db_O_hqv-g?pwd1234 提取码&#xff1a;1234 一、路线 我在了解这个舵机之前最像想看到的是一个完全的路径。 比如我想学习b站上那个智能门锁&#xff0c;那就得每个模块的基本代码都会才能结合各…

​​​【收录 Hello 算法】第 10 章 搜索

目录 第 10 章 搜索 本章内容 第 10 章 搜索 搜索是一场未知的冒险&#xff0c;我们或许需要走遍神秘空间的每个角落&#xff0c;又或许可以快速锁定目标。 在这场寻觅之旅中&#xff0c;每一次探索都可能得到一个未曾料想的答案。 本章内容 10.1 二分查找10.2 二…

智慧展厅设计的难点有哪些

1、运用先进的展示技术 将全息影像、三维投影、虚拟现实、人机互动等技术做做完美衔接&#xff0c;把展厅的内容展示做到丰富多彩&#xff0c;从而让展厅富有科技感和艺术性。 2、内容要生动有趣 从而更好地吸引参观者。展厅设计师要与客户有良好深入的沟通&#xff0c;搜集与整…

struct.unpack_from()学习笔记

struct.unpack_from(fmt,b_data,offset) 按照指定的格式fmt&#xff0c;从偏移位置offset&#xff0c;对b_data开始解包&#xff0c;返回数据格式是一个元组(v1,v2…) fmt可以有&#xff1a; _struct.py: The remaining chars indicate types of args and must match exactly;…

WPF之容器标签之Canvas布局标签

Canvas: 定义一个区域&#xff0c;可在其中使用相对于 Canvas 区域的坐标以显式方式来定位子元素。 实例 可以在子标签使用Canvas属性设置定位 <Canvas Width"500" Height"300"><StackPanel Width"100" Height"100"Backgro…

详解最新版RabbitMQ 基于RPM 方式的安装

如何选择安装版本 已经不支持的发布系列 版本最后补丁版本首次发布时间停止更新时间3.73.7.282017年11月28日2020年09月30日3.63.6.162015年12月22日2018年05月31日3.53.5.82015年03月11日2016年10月31日3.43.4.42014年10月21日2015年10月31日3.33.3.52014年04月02日2015年03…

列表元素添加的艺术:从单一到批量

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、向列表中添加单一元素 1. append方法 2. insert方法 三、向列表中添加批量…

2024年学浪视频怎么下载到手机相册

随着2024年的到来&#xff0c;学浪平台继续为广大学习者提供优质的在线教育资源。然而&#xff0c;如何将这些宝贵的视频内容下载到手机相册&#xff0c;方便随时离线观看呢&#xff1f;无论您是想在旅途中学习&#xff0c;还是希望在没有网络的情况下复习课程&#xff0c;本文…

网络层协议——IP协议

目录 一、IP协议 二、IP协议格式 三、网段划分 四、私网IP地址和公网IP地址 五、路由 一、IP协议 IP指网际互连协议&#xff0c;Internet Protocol的缩写&#xff0c;是TCP/IP体系中的网络层协议。 IP协议主要作用是提供一种能力&#xff0c;将数据从A主机传送到B主机的能力…

转行3年涨薪300%,我总结了一套产品经理快速入门指南!

想转行的产品小白&#xff0c;初期一定会遇到这个问题——我要如何 0 基础转行产品经理&#xff1f; 要想 0 基础快速转行产品经理&#xff0c;我通过个人实践总结了 5 个关键点&#xff0c;可以参考。 一、熟悉产品经理的工作全流程 转行的产品小白&#xff0c;首先要建立产…