一、开启二级缓存

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. 2021/2/5 关于new的一个教训

    千万不要在类构造函数的初始化里new任何东西,这会导致析构函数delete一个野指针!构造函数一定要把所有的指针初始化为nullptr! 以下代码会报错(堆内存崩溃): Integer::Intege ...

  2. C语言字符串处理库函数大全(转)

    一.string.h中字符串处理函数 在头文件<string.h>中定义了两组字符串函数.第一组函数的名字以str开头:第二组函数的名字以mem开头. 只有函数memmove对重叠对象间的 ...

  3. SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!

    大家好,我是飘渺. 今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常. 首先我们来看看为什么要返回统一的标准格式? 为什么要对Sp ...

  4. 「AGC021E」Ball Eat Chameleons

    「AGC021E」Ball Eat Chameleons 考虑如何判定一个合法的颜色序列. 不妨设颜色序列中有 \(R\) 个红球,\(B\) 个蓝球,所以有 \(R+B=k\). 考虑分情况讨论: ...

  5. [WPF] 使用 Visual Studio App Center 持续监视应用使用情况和问题

    1. 什么是AppCenter Visual Studio App Center 是几个常见移动开发和云集成服务(如持续集成.持续交付和自动 UI 测试等服务)的集合. 这些 App Center 服 ...

  6. 【LeetCode】1207. 独一无二的出现次数

    1207. 独一无二的出现次数 知识点:set:哈希表 题目描述 给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数. 如果每个数的出现次数都是独一无二的,就返回 true:否则返回 fal ...

  7. windows 10家庭版安装SQL Server 2014出现.net 3.5失败问题解决。

    在安装SQL Server 2014的过程中,出现.net 3.5缺失,导致失败问题. 后来,研究了下,解决思路如下: 先将电脑更新到了windows 10专业版,(因为需要用到专业版才有的组策略管理 ...

  8. sql server 查看数据库配置等信息(字符集,编码格式,版本号...)

    select SERVERPROPERTY(N'edition') as Edition --数据版本,如企业版.开发版等,SERVERPROPERTY(N'collation') as Collat ...

  9. 文本生成器(AC自动机+dp)

    F. 文本生成器 内存限制:512 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 原题来自:JSOI 2007 JSOI 交给队员 ZYX 一个任务,编 ...

  10. java中 字符串的构造方法和直接创建

    java.long.String类代表字符串.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现.(程序当中所有的双引号字符串,都是String类的对象[没 ...