一、开启二级缓存

cache-enabled: true

# mybatis-plus相关配置
mybatis-plus:
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:mapper/*.xml
# 以下配置均有默认值,可以不设置
global-config:
db-config:
#主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
field-strategy: NOT_EMPTY
#数据库类型
db-type: ORACLE
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 一级缓存配置 一级缓存是本地或者说局部缓存,它不能被关闭,只能配置缓存范围。SESSION 或者 STATEMENT。
local-cache-scope: session
# 二级缓存总开关
cache-enabled: true

二、添加缓存注解

@EnableCaching

@SpringBootApplication
@MapperScan({"com.qiang.mybaties.plus.test.cache.dao"})
@EnableCaching
public class MybatiesPlusCacheApplication {
public static void main(String[] args) {
SpringApplication.run(MybatiesPlusCacheApplication.class, args);
}
}

三、实体类实现接口

Serializable

@Data
public class Account extends Model<Account> implements Serializable{ private Integer id; private Integer balance; private Integer freezeMoney; /**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}

四、配置Redis模板

RedisConfig

@Configuration
public class RedisConfig { /**
* 配置RedisTemplate
*
* @param factory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory, Jackson2JsonRedisSerializer serializer) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
// redis连接工厂
template.setConnectionFactory(factory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// redis.key序列化器
template.setKeySerializer(stringRedisSerializer);
// redis.value序列化器
template.setValueSerializer(serializer);
// redis.hash.key序列化器
template.setHashKeySerializer(stringRedisSerializer);
// redis.hash.value序列化器
template.setHashValueSerializer(serializer);
// 调用其他初始化逻辑
template.afterPropertiesSet();
// 这里设置redis事务一致
template.setEnableTransactionSupport(true);
return template;
} /**
* 配置redis Json序列化器
*
* @return
*/
@Bean
public Jackson2JsonRedisSerializer redisJsonSerializer() {
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
return serializer;
}
}

五、配置Redis缓存

RedisCache

public final class RedisCache implements Cache {

    /**
* 日志
*/
private static final Logger logger = LogManager.getLogger(RedisCache.class); /**
* 读写锁
*/
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
/**
* ID,获取缓存对象的唯一标识
*/
private String id; /**
* redisTemplate
*/
private static RedisTemplate redisTemplate; public RedisCache(String id) {
if (id == null) {
throw new IllegalArgumentException("缓存实例需要一个id!");
} else {
logger.info("开启Redis缓存: id = {}", id);
this.id = id;
}
} @Override
public String getId() {
return this.id;
} @Override
public int getSize() {
try {
if (redisTemplate == null) {
redisTemplate = getRedisTemplate();
}
Long size = redisTemplate.opsForHash().size(this.id.toString());
logger.info("Redis缓存大小: id = {}, size = {}", id, size);
return size.intValue();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
} @Override
public void putObject(final Object key, final Object value) {
try {
if (redisTemplate == null) {
redisTemplate = getRedisTemplate();
}
logger.info("设置Redis缓存: id = {}, key = {}, value = {}", id, key, value);
redisTemplate.opsForHash().put(this.id.toString(), key.toString(), value);
} catch (Exception e) {
e.printStackTrace();
}
} @Override
public Object getObject(final Object key) {
try {
if (redisTemplate == null) {
redisTemplate = getRedisTemplate();
}
Object hashVal = redisTemplate.opsForHash().get(this.id.toString(), key.toString());
logger.info("获取Redis缓存: id = {}, key = {}, hashVal = {}", id, key, hashVal);
return hashVal;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} @Override
public Object removeObject(final Object key) {
try {
if (redisTemplate == null) {
redisTemplate = getRedisTemplate();
}
redisTemplate.opsForHash().delete(this.id.toString(), key.toString());
logger.info("移除Redis缓存: id = {}, key = {}", id, key);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} @Override
public void clear() {
try {
if (redisTemplate == null) {
redisTemplate = getRedisTemplate();
}
redisTemplate.delete(this.id.toString());
logger.info("清空Redis缓存: id = {}", id);
} catch (Exception e) {
e.printStackTrace();
}
} @Override
public ReadWriteLock getReadWriteLock() {
return this.readWriteLock;
} @Override
public String toString() {
return "RedisCache {" + this.id + "}";
} /**
* 由于启动期间注入失败,只能运行期间注入
*
* @return
*/
public RedisTemplate getRedisTemplate() {
redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate");
return redisTemplate;
} }

SpringUtil

@Component
public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
} public static Object getBean(String name) {
return 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);
}
}

六、在Dao层使用

AccountDao,此时,MybatiesPlus自带的方法缓存已经生效。但是Xml文件里的方法还未生效,接着下一步

// 使用缓存
@CacheNamespace(implementation= RedisCache.class,eviction=RedisCache.class)
public interface AccountDao extends BaseMapper<Account> { /**
* 查询去重的Balance
* @return
*/
List<Account> selectDistinctBalance(); /**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
Account queryById(Integer id); /**
* 查询指定行数据
*
* @param offset 查询起始位置
* @param limit 查询条数
* @return 对象列表
*/
List<Account> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit); /**
* 通过实体作为筛选条件查询
*
* @param account 实例对象
* @return 对象列表
*/
List<Account> queryAll(Account account); /**
* 新增数据
*
* @param account 实例对象
* @return 影响行数
*/
int insertOne(Account account); /**
* 修改数据
*
* @param account 实例对象
* @return 影响行数
*/
int update(Account account); /**
* 通过主键删除数据
*
* @param id 主键
* @return 影响行数
*/
int deleteById(Integer id);
}

七、在Xml文件使用

AccountDao.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.qiang.mybaties.plus.test.cache.dao.AccountDao"> <resultMap id="AccountMap" type="com.qiang.mybaties.plus.test.cache.entity.Account">
<result property="id" column="ID" jdbcType="INTEGER"/>
<result property="balance" column="BALANCE" jdbcType="INTEGER"/>
<result property="freezeMoney" column="FREEZE_MONEY" jdbcType="INTEGER"/>
</resultMap>
<!-- 使用缓存 -->
<cache-ref namespace="com.qiang.mybaties.plus.test.cache.dao.AccountDao"/> <sql id="Base_Column_List">
ID, BALANCE, FREEZE_MONEY
</sql>
<select id="selectDistinctBalance" resultType="com.qiang.mybaties.plus.test.cache.entity.Account">
SELECT DISTINCT
( BALANCE ),
ID,
FREEZE_MONEY
FROM
ACCOUNT
</select> <!--查询单个-->
<select id="queryById" resultMap="AccountMap">
select
ID, BALANCE, FREEZE_MONEY
from TEST.ACCOUNT
where ID = #{id}
</select> <!--查询指定行数据-->
<select id="queryAllByLimit" resultMap="AccountMap">
select
ID, BALANCE, FREEZE_MONEY
from TEST.ACCOUNT
limit #{offset}, #{limit}
</select> <!--通过实体作为筛选条件查询-->
<select id="queryAll" resultMap="AccountMap">
select
ID, BALANCE, FREEZE_MONEY
from TEST.ACCOUNT
<where>
<if test="id != null">
and ID = #{id}
</if>
<if test="balance != null">
and BALANCE = #{balance}
</if>
<if test="freezeMoney != null">
and FREEZE_MONEY = #{freezeMoney}
</if>
</where>
</select> <!--新增所有列-->
<insert id="insertOne" keyProperty="id" useGeneratedKeys="true">
insert into TEST.ACCOUNT(BALANCE, FREEZE_MONEY)
values (#{balance}, #{freezeMoney})
</insert> <!--通过主键修改数据-->
<update id="update">
update TEST.ACCOUNT
<set>
<if test="balance != null">
BALANCE = #{balance},
</if>
<if test="freezeMoney != null">
FREEZE_MONEY = #{freezeMoney},
</if>
</set>
where ID = #{id}
</update> <!--通过主键删除-->
<delete id="deleteById">
delete from TEST.ACCOUNT where ID = #{id}
</delete> </mapper>

八、验证是否成功

8.1 作用域为自带方法

测试代码

	@Test
public void testRedisCacheCommon(){
// 测试 mybaties-plus 中间件为redis 作用域为 mybaties自带方法 的二级缓存
List<Account> list1 = accountService.list();
System.out.println(list1);
List<Account> list2 = accountService.list();
System.out.println(list2);
}

结果看到第二次查询使用了缓存

Redis也成功添加缓存

缓存更新

	@Test
public void testRedisCacheCommon(){
// 测试 mybaties-plus 中间件为redis 作用域为 mybaties自带方法 的二级缓存
List<Account> list1 = accountService.list();
System.out.println(list1);
boolean b = accountService.removeById(2);
System.out.println(b);
List<Account> list2 = accountService.list();
System.out.println(list2);
}

结果看到查询了两次数据库,当缓存作用在同一个CacheNamespace时候,发生增删改操作,则缓存更新

8.2 作用域为Xml文件

测试代码

	@Test
public void testRedisCacheByXml() {
// 测试 mybaties-plus 中间件为redis 作用域为 xml文件 的二级缓存
Account account = new Account();
account.setId(1);
List<Account> accounts1 = accountService.queryAll(account);
System.out.println(accounts1);
List<Account> accounts2 = accountService.queryAll(account);
System.out.println(accounts2);
}

结果看到第二次查询使用了缓存

Redis也成功添加缓存

缓存更新

	@Test
public void testRedisCacheByXml() {
// 测试 mybaties-plus 中间件为redis 作用域为 xml文件 的二级缓存
Account account = new Account();
account.setId(1);
List<Account> accounts1 = accountService.queryAll(account);
System.out.println(accounts1);
int i = accountService.deleteById(1);
System.out.println(i);
List<Account> accounts2 = accountService.queryAll(account);
System.out.println(accounts2);
}

结果看到查询了两次数据库,当缓存作用在同一个CacheNamespace时候,发生增删改操作,则缓存更新

作者(Author):小强崽

来源(Source):https://www.wuduoqiang.com/archives/MyBatiesPlus+Redis分布式缓存

协议(License):署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)

版权(Copyright):商业转载请联系作者获得授权,非商业转载请注明出处。 For commercial use, please contact the author for authorization. For non-commercial use, please indicate the source.

MyBatiesPlus+Redis分布式缓存的更多相关文章

  1. 基于redis分布式缓存实现

    Redis的复制功能是完全建立在之前我们讨论过的基 于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redis的复制功能,就一定会有内存快照发生,那么首先要注意你 的 ...

  2. fourinone分布式缓存研究和Redis分布式缓存研究

    最近在写一个天气数据推送的项目,准备用缓存来存储数据.下面分别介绍一下fourinone分布式缓存和Redis分布式缓存,然后对二者进行对比,以供大家参考. 1  fourinone分布式缓存特性 1 ...

  3. Redis 分布式缓存 Java 框架

    为什么要在 Java 分布式应用程序中使用缓存? 在提高应用程序速度和性能上,每一毫秒都很重要.根据谷歌的一项研究,假如一个网站在3秒钟或更短时间内没有加载成功,会有 53% 的手机用户会离开. 缓存 ...

  4. c#实例化继承类,必须对被继承类的程序集做引用 .net core Redis分布式缓存客户端实现逻辑分析及示例demo 数据库笔记之索引和事务 centos 7下安装python 3.6笔记 你大波哥~ C#开源框架(转载) JSON C# Class Generator ---由json字符串生成C#实体类的工具

    c#实例化继承类,必须对被继承类的程序集做引用   0x00 问题 类型“Model.NewModel”在未被引用的程序集中定义.必须添加对程序集“Model, Version=1.0.0.0, Cu ...

  5. Redis分布式缓存实现

    基于redis分布式缓存实现 第一:Redis是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data S ...

  6. 基于redis分布式缓存实现(新浪微博案例)

    第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data Structure)需求越来 ...

  7. 组件-------(一)redis系列--安装部署redis+实现redis分布式缓存 java+Spring+redis

    目的:解决单机session不能共享问题,插入查询数据库时间效率问题,实现分布式缓存. 准备材料:Redis 下载链接 http://pan.baidu.com/s/1dEGTxvV 相关jar包如果 ...

  8. 基于redis分布式缓存实现(新浪微博案例)转

    第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data Structure)需求越来 ...

  9. Spring Boot Redis 分布式缓存的使用

    一.pom 依赖 <!-- 分布式缓存 --> <dependency> <groupId>org.springframework.boot</groupId ...

随机推荐

  1. Go nuts

    含义: to behave in a crazy, enthusiastic, or violent way. 发起狂来 详细讲解 go 在这里也不是"去"的意思,而是和 get. ...

  2. take for granted

    解释含义1 Take for granted是一句地道的英语口语,意思是to expect someone to always be there and do things for you even ...

  3. Macbook(M1版)的用户看过来,.net 6 Preview 6支持Apple Silicon for macOS

    本文由葡萄城技术团队翻译 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 我们很高兴发布.NET6预览的第6版,本次预览是倒数第二次预览了.在本次预览发布之 ...

  4. python删除文件中某一行

    将文本中的 tasting123删除 with open("fileread.txt","r",encoding="utf-8") as f ...

  5. 12. Mysql基础入门

    课程大纲 • 数据库概述 • MySQL基本操作 • MySQL索引基础 • MySQL高级特性

  6. ES6 let const关键字

    在es6中,引入了let和const关键字: 1.letES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. (1)在块级作用域里有效(比 ...

  7. this的四种用法!

    经常会有人问到this的用法,其实简单来说,this有四种应用场景,分别是在构造函数上.对象属性中.普通函数中.call和apply方法中. 首先我们来看第一种:在构造函数中的用法 第二种是在在对象属 ...

  8. python + Poium 库操作

    1.支持pip安装 pip install poium 2.基本用法 from poium import PageElement,Page,PageElements# 1.poium支持的8种定位方法 ...

  9. 在线体验 Windows 11「GitHub 热点速览 v.21.30」

    作者:HelloGitHub-小鱼干 有什么比无需安装系统,检测硬件兼容度,只要打开一个浏览器,输入某个神秘的地址回车,即可体验 Windows 11 更棒的呢?windows11 就是这么一个小工具 ...

  10. iOS 15 Beta升级卡死在更新进程,无法启动怎么办?

    2021苹果全球开发者大会结束后,大批果粉迫不及待的尝试升级iOS 15测试版本,想第一时间体验新功能. 但是许多用户反馈升级一直卡死在"准备更新"."验证更新" ...