Mybatis Cache(二)MybatisCache+Redis

news2025/2/23 22:22:24

前面提到了,使用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都清除了。

二、缺点

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙系统与OpenHarmony:中国科技行业的新动力与就业前景

背景 经历近年来的迅猛发展&#xff0c;鸿蒙原生应用数量已突破4000款&#xff0c;生态设备数量超过8亿台&#xff0c;开发者群体壮大至220万人。更为显著的是&#xff0c;鸿蒙系统在中国市场的份额已经超过了15%&#xff0c;稳居第三大操作系统&#xff0c;其生态之树已然枝繁…

牛客NC236 最大差值【simple 动态规划 Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/a01abbdc52ba4d5f8777fb5dae91b204 思路 不难看出该题可以使用动态规划的方式解题。 在循环数组的过程中&#xff0c;记录截止到当前位置-1的最小值&#xff0c; 然后用当前的值去计算最大的差值。Java代码 im…

【软件设计师】下午题总结-数据流图、数据库、统一建模语言

下午题总结 1 试题一1.1 结构化语言 2 试题二弱实体增加权限增加实体间联系和联系的类型 3 试题三3.1 UML关系例子 3.2 例子&#xff08;2016上半年&#xff09;3.3 设计类分类3.3.1 接口类3.3.2 控制类3.3.3 实体类 3.4 简答题3.4.1 简要说明选择候选类的原则3.4.2 某个类必须…

【NOIP2014普及组复赛】题4:子矩阵

题3&#xff1a;子矩阵 【题目描述】 给出如下定义&#xff1a; 1.子矩阵&#xff1a;从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵&#xff08;保持行与列的相对顺序&#xff09;被称为原矩阵的一个子矩阵。 例如&#xff0c;下面左图中选取第 2 、 4 2、4 2、…

结构安全预警?事前发现?人工观测VS自动化监测,谁更胜一筹?

人工检测是依靠目测检查或借助于便携式仪器测量得到的信息&#xff0c;但是随着整个行业的发展&#xff0c;传统的人工检测方法已经不能满足检测需求&#xff0c;从人工检测到自动化监测已是必然趋势。 a. 从检测方式看 人工检测需要耗费大量的精力&#xff0c;从摆放检测工具到…

web前端的路径和Servlet注解开发

目录 在web前端的两种路径 绝对路径的两种写法 相对路径 相对路径进阶 使用注解开发Servlet 使用注解开发Servlet的注意事项 使用idea创建servlet模板 在web前端的两种路径 绝对路径的两种写法 1.带网络三要素 http://ip地址:端口号/资源路径 2.不带网络三要素 /资源路…

Java开发大厂面试第17讲:MySQL 的优化方案有哪些?数据库设计、查询优化、索引优化、硬件和配置优化等

性能优化&#xff08;Optimize&#xff09;指的是在保证系统正确性的前提下&#xff0c;能够更快速响应请求的一种手段。而且有些性能问题&#xff0c;比如慢查询等&#xff0c;如果积累到一定的程度或者是遇到急速上升的并发请求之后&#xff0c;会导致严重的后果&#xff0c;…

Springboot开发 -- Postman 调试类型详解

引言 在 Spring Boot 应用开发过程中&#xff0c;接口测试是必不可少的一环。Postman 作为一款强大的 API 开发和测试工具&#xff0c;可以帮助开发者轻松构建、测试和管理 HTTP 请求。本文将为大家介绍如何在 Spring Boot 开发中使用 Postman 进行接口测试。 一、准备工作 安…

Three.js点与材质(Points)

球几何体 // 创建球几何体 const sphereGeometry new THREE.SphereGeometry(3, 20, 20) const material new THREE.MeshBasicMaterial({color: 0xff0000,wireframe: true // 以线框的形式显示顶点 }) const mesh new THREE.Mesh(sphereGeometry, material) scene.add(mesh)点…

淘宝订单系统ERP中如何接入平台订单信息?(订单API)

淘宝开放平台中有交易API&#xff0c;里面有各种关于交易的API接口。但是申报应用权限的审核流程严格又漫长。不少公司费时费力的申请后&#xff0c;结果还是没有审批下来。 调用淘宝自定义接口custom&#xff0c;可以实现淘宝开放平台API的调用。技术人员会根据您需要的接口做…

力扣第141题和142题-环形链表,是否有环,环的入口节点

因这2道题均不改变链表结构&#xff0c;所以可以不创建新的临时头结点 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ bool hasCycle(struct ListNode *head) {if(headNULL||head->nextNULL)//若只有一个数…

恶劣天候鲁棒三维目标检测论文整理

恶劣天候鲁棒三维目标检测论文整理 Sunshine to Rainstorm: Cross-Weather Knowledge Distillation for Robust 3D Object DetectionRobo3D: Towards Robust and Reliable 3D Perception against CorruptionsLossDistillNet: 3D Object Detection in Point Cloud Under Harsh W…

2024目前网上最火短剧机器人做法,自动搜索发剧 自动更新资源 自动分享资源

目前整个项目圈子很多的短剧机器人&#xff0c;我写的&#xff0c;自动搜索发剧&#xff0c;自动更新资源&#xff0c;自动分享资源&#xff0c;前段时间大部分做短剧的都是做的短剧分成&#xff0c;我的一个学员做的30W播放量才200块收益&#xff0c;备受启发&#xff0c;我就…

迷你手持小风扇到底哪个牌子最好?揭秘迷你手持手持小风扇排行榜

在炎炎夏日&#xff0c;迷你手持小风扇成为了我们不可或缺的清凉伴侣。然而&#xff0c;面对市场上琳琅满目的品牌&#xff0c;迷你手持小风扇到底哪个牌子最好&#xff1f;今天&#xff0c;我将揭秘迷你手持小风扇排行榜&#xff0c;带大家一探各大品牌的魅力&#xff0c;让你…

交叉编译程序,提示 incomplete type “struct sigaction“ is not allowed

问题描述 incomplete type "struct sigaction" is not allowed解决办法 在代码的最顶端添加如下代码即可 #define _XOPEN_SOURCE此定义不是简单的宏定义&#xff0c;是使程序符合系统环境的不可缺少的部分 _XOPEN_SOURCE为了实现XPG&#xff1a;The X/Open Porta…

Vitis HLS 学习笔记--抽象并行编程模型-控制驱动与数据驱动

目录 1. 简介 2. Takeaways 3. Data-driven Task-level Parallelism 3.1 simple_data_driven 示例 3.2 分析 hls::task 类 3.3 分析通道(Channel) 3.4 注意死锁 4. Control-driven Task-level Parallelism 4.1 理解控制驱动的 TLP 4.2 simple_control_driven 示例 4…

59 多次 mmap 虚拟地址的关系

前言 这是来自于网友的一篇帖子 然后 我们这里来探究一下这个问题 主要是 多次连续的 mmap 获取到的 虚拟地址区域 是否连续 以及 衍生出的一些其他的问题 从 mmap 的实现 我们可以知道, mmap 的空间是 自顶向下 分配的, 因此 两块空间应该是连续的, 第一块在上面, 第二块…

二百三十七、Hive——DWS层生成每个清洗字段的异常情况记录

一、目的 在Hive中对每种业务数据的清洗字段的异常数据进行记录 例如这张图&#xff0c;上面是原始数据&#xff0c;下面是每台雷达每天的异常字段的记录 二、实施步骤 &#xff08;一&#xff09;建表 create table if not exists dws_data_clean_record_queue(data_ty…

Go团队:Go是什么

2024年的Google I/O大会[1]如期而至。 这届大会的核心主旨毫无疑问是坚定不移的以AI为中心&#xff1a;Google先是发布了上下文长度将达到惊人的200万token的Gemini 1.5 Pro[2]&#xff0c;然后面对OpenAI GPT-4o的挑衅&#xff0c;谷歌在大会上直接甩出大杀器Project Astra[3]…

关于pytest中用例名称使用中文乱码的解决

场景&#xff1a;使用pytest.mark.parametrize装饰器为用例自定义名称时&#xff0c;运行显示乱码。如下图所示&#xff1a; 解决方案&#xff1a; 1.在根目录 pytest.ini中增加一行代码 [pytest] disable_test_id_escaping_and_forfeit_all_rights_to_community_supportTrue…