开启mybatis二级缓存-使用redis存储缓存
This commit is contained in:
parent
f0f0b6e3c4
commit
4f38f3be63
@ -126,7 +126,7 @@ yarn run dev
|
||||
- [x] 引入Guava RateLimiter(单机) 和 Redisson RateLimiter(分布式) 两种限流机制
|
||||
- [x] 支持用户对失败的图表进行手动重试
|
||||
- [ ] 图表数据分表存储,提高查询灵活性和性能
|
||||
- [ ] 引入redis缓存提高加载速度
|
||||
- [x] 引入redis缓存提高加载速度
|
||||
- [ ] 给任务执行增加 guava Retrying重试机制,保证系统可靠性
|
||||
- [ ] 定时任务把失败状态的图表放到队列中(补偿机制)
|
||||
- [ ] 给任务的执行增加超时时间,超时自动标记为失败(超时控制)
|
||||
|
||||
4
pom.xml
4
pom.xml
@ -17,10 +17,6 @@
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
package top.peng.answerbi;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@ -13,9 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
* @author yunpeng
|
||||
* @version 1.0 2023/5/16
|
||||
*/
|
||||
// todo 如需开启 Redis,须移除 exclude 中的内容
|
||||
@SpringBootApplication(exclude = {RedisAutoConfiguration.class})
|
||||
@MapperScan("top.peng.answerbi.mapper")
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||
public class MainApplication {
|
||||
|
||||
@ -66,7 +66,7 @@ public class BiMqConfig {
|
||||
.to(biExchange())
|
||||
.with(BiMqConstant.BI_ROUTING_KEY);
|
||||
}
|
||||
//绑定Bi分析业务队列到Bi分析业务交换机
|
||||
//绑定死信队列到死信交换机
|
||||
@Bean
|
||||
public Binding DeadLetterBinding(){
|
||||
return BindingBuilder
|
||||
|
||||
@ -14,7 +14,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
* @version 1.0 2023/5/16
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("top.peng.springbootinit.mapper")
|
||||
@MapperScan("top.peng.answerbi.mapper")
|
||||
public class MyBatisPlusConfig {
|
||||
|
||||
/**
|
||||
|
||||
79
src/main/java/top/peng/answerbi/config/RedisConfig.java
Normal file
79
src/main/java/top/peng/answerbi/config/RedisConfig.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* @(#)RedisTemplateConfig.java
|
||||
*
|
||||
* Copyright © 2023 YunPeng Corporation.
|
||||
*/
|
||||
package top.peng.answerbi.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* RedisTemplateConfig
|
||||
*
|
||||
* @author yunpeng
|
||||
* @version 1.0 2023/7/27
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Bean(name = "redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory){
|
||||
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(factory);
|
||||
// 使用Jackson2JsonRedisSerialize 替换默认序列化
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
|
||||
// 设置key和value的序列化规则
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
//afterPropertiesSet和init-method之间的执行顺序是afterPropertiesSet 先执行,init - method 后执行。
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager(RedisTemplate<Object,Object> redisTemplate) {
|
||||
|
||||
//基本配置
|
||||
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
|
||||
//设置 key 为String
|
||||
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getStringSerializer()))
|
||||
//设置 value 为自动转Json 的Object
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()))
|
||||
//不缓存 null
|
||||
.disableCachingNullValues()
|
||||
//配置缓存失效时间30分钟
|
||||
.entryTtl(Duration.ofMinutes(30));
|
||||
//构造一个redis缓存管理器
|
||||
return RedisCacheManager.RedisCacheManagerBuilder
|
||||
.fromConnectionFactory(Objects.requireNonNull(redisTemplate.getConnectionFactory()))
|
||||
.cacheDefaults(defaultCacheConfig)
|
||||
//配置同步修改或删除
|
||||
.transactionAware()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* @(#)MyBatisRedisCache.java
|
||||
*
|
||||
* Copyright © 2023 YunPeng Corporation.
|
||||
*/
|
||||
package top.peng.answerbi.manager;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.cache.Cache;
|
||||
import org.springframework.data.redis.connection.RedisServerCommands;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import top.peng.answerbi.utils.SpringContextUtils;
|
||||
|
||||
/**
|
||||
* MyBatisRedisCache mybaits 缓存工具类
|
||||
*
|
||||
* @author yunpeng
|
||||
* @version 1.0 2023/7/27
|
||||
*/
|
||||
@Slf4j
|
||||
public class MybatisRedisCacheManager implements Cache {
|
||||
|
||||
private RedisTemplate<Object,Object> redisTemplate;
|
||||
|
||||
// 读写锁
|
||||
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
|
||||
|
||||
// cache instance id
|
||||
private final String id;
|
||||
|
||||
private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间
|
||||
|
||||
public MybatisRedisCacheManager(String id) {
|
||||
if (id == null) {
|
||||
throw new IllegalArgumentException("Cache instances require an ID");
|
||||
}
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put query result to redis
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
public void putObject(Object key, Object value) {
|
||||
getRedisTemplate().opsForValue().set(key.toString(), value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
|
||||
log.info("Put query result to redis, key={}",key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(Object key) {
|
||||
try {
|
||||
log.info("Get cached query result from redis, key={}",key);
|
||||
return getRedisTemplate().opsForValue().get(key.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("Get cached query result from redis failed , key={}",key);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object removeObject(Object key) {
|
||||
if (key != null){
|
||||
getRedisTemplate().delete(key.toString());
|
||||
log.info("Remove cached query result from redis, key={}",key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Set<Object> keys = getRedisTemplate().keys("*:" + this.id + "*");
|
||||
if (!CollectionUtils.isEmpty(keys)) {
|
||||
getRedisTemplate().delete(keys);
|
||||
}
|
||||
log.info("Clear all the cached query result from redis");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
Long size = getRedisTemplate().execute(RedisServerCommands::dbSize);
|
||||
if (size == null) return 0;
|
||||
return size.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadWriteLock getReadWriteLock() {
|
||||
return readWriteLock;
|
||||
}
|
||||
|
||||
private RedisTemplate<Object,Object> getRedisTemplate(){
|
||||
//通过SpringContextUtils工具类获取RedisTemplate
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = (RedisTemplate<Object,Object>) SpringContextUtils.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package top.peng.answerbi.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.CacheNamespace;
|
||||
import top.peng.answerbi.manager.MybatisRedisCacheManager;
|
||||
import top.peng.answerbi.model.entity.Chart;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
@ -7,8 +9,9 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
* @author yunpeng.zhang
|
||||
* @description 针对表【chart(图表信息表)】的数据库操作Mapper
|
||||
* @createDate 2023-07-10 16:45:42
|
||||
* @Entity top.peng.springbootinit.model.entity.Chart
|
||||
* @Entity top.peng.answerbi.model.entity.Chart
|
||||
*/
|
||||
@CacheNamespace(implementation = MybatisRedisCacheManager.class)
|
||||
public interface ChartMapper extends BaseMapper<Chart> {
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
package top.peng.answerbi.mapper;
|
||||
|
||||
import top.peng.answerbi.model.entity.User;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.CacheNamespace;
|
||||
import top.peng.answerbi.manager.MybatisRedisCacheManager;
|
||||
import top.peng.answerbi.model.entity.User;
|
||||
|
||||
/**
|
||||
* @author yunpeng.zhang
|
||||
* @description 针对表【user(用户)】的数据库操作Mapper
|
||||
* @createDate 2023-07-10 16:45:42
|
||||
* @Entity top.peng.springbootinit.model.entity.User
|
||||
* @Entity top.peng.answerbi.model.entity.User
|
||||
*/
|
||||
@CacheNamespace(implementation = MybatisRedisCacheManager.class)
|
||||
public interface UserMapper extends BaseMapper<User> {
|
||||
|
||||
}
|
||||
|
||||
@ -3,17 +3,6 @@ package top.peng.answerbi.service.impl;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import top.peng.answerbi.common.ErrorCode;
|
||||
import top.peng.answerbi.constant.CommonConstant;
|
||||
import top.peng.answerbi.exception.BusinessException;
|
||||
import top.peng.answerbi.mapper.UserMapper;
|
||||
import top.peng.answerbi.model.dto.user.UserQueryRequest;
|
||||
import top.peng.answerbi.model.entity.User;
|
||||
import top.peng.answerbi.model.enums.UserRoleEnum;
|
||||
import top.peng.answerbi.model.vo.LoginUserVO;
|
||||
import top.peng.answerbi.model.vo.UserVO;
|
||||
import top.peng.answerbi.service.UserService;
|
||||
import top.peng.answerbi.utils.SqlUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@ -23,7 +12,18 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import top.peng.answerbi.common.ErrorCode;
|
||||
import top.peng.answerbi.constant.CommonConstant;
|
||||
import top.peng.answerbi.constant.UserConstant;
|
||||
import top.peng.answerbi.exception.BusinessException;
|
||||
import top.peng.answerbi.mapper.UserMapper;
|
||||
import top.peng.answerbi.model.dto.user.UserQueryRequest;
|
||||
import top.peng.answerbi.model.entity.User;
|
||||
import top.peng.answerbi.model.enums.UserRoleEnum;
|
||||
import top.peng.answerbi.model.vo.LoginUserVO;
|
||||
import top.peng.answerbi.model.vo.UserVO;
|
||||
import top.peng.answerbi.service.UserService;
|
||||
import top.peng.answerbi.utils.SqlUtils;
|
||||
|
||||
/**
|
||||
* 用户服务实现
|
||||
@ -60,7 +60,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
// 账户不能重复
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_account", userAccount);
|
||||
long count = this.baseMapper.selectCount(queryWrapper);
|
||||
long count = this.count(queryWrapper);
|
||||
if (count > 0) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
|
||||
}
|
||||
@ -96,7 +96,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_account", userAccount);
|
||||
queryWrapper.eq("user_password", encryptPassword);
|
||||
User user = this.baseMapper.selectOne(queryWrapper);
|
||||
User user = this.getOne(queryWrapper);
|
||||
// 用户不存在
|
||||
if (user == null) {
|
||||
log.info("user login failed, userAccount cannot match userPassword");
|
||||
|
||||
@ -16,9 +16,9 @@ spring:
|
||||
port: 6379
|
||||
timeout: 5000
|
||||
password: 123456
|
||||
# Elasticsearch 配置
|
||||
# todo 需替换配置
|
||||
elasticsearch:
|
||||
uris: http://localhost:9200
|
||||
username: root
|
||||
password: 123456
|
||||
# rabbitMq 配置
|
||||
rabbitmq:
|
||||
host: localhost
|
||||
port: 5672
|
||||
username: guest
|
||||
password: guest
|
||||
@ -2,26 +2,24 @@ server:
|
||||
port: 8101
|
||||
spring:
|
||||
# 数据库配置
|
||||
# todo 需替换配置
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/answer_bi
|
||||
username: root
|
||||
password: 123456
|
||||
# Redis 配置
|
||||
# todo 需替换配置
|
||||
redis:
|
||||
database: 1
|
||||
host: localhost
|
||||
port: 6379
|
||||
timeout: 5000
|
||||
password: 123456
|
||||
# Elasticsearch 配置
|
||||
# todo 需替换配置
|
||||
elasticsearch:
|
||||
uris: http://localhost:9200
|
||||
username: root
|
||||
password: 123456
|
||||
# rabbitMq 配置
|
||||
rabbitmq:
|
||||
host: localhost
|
||||
port: 5672
|
||||
username: guest
|
||||
password: guest
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
# 生产环境关闭日志
|
||||
|
||||
@ -10,8 +10,7 @@ spring:
|
||||
matching-strategy: ant_path_matcher
|
||||
# session 配置
|
||||
session:
|
||||
# todo 取消注释开启分布式 session(须先配置 Redis)
|
||||
# store-type: redis
|
||||
store-type: redis
|
||||
# 30 天过期
|
||||
timeout: 2592000
|
||||
# 数据库配置
|
||||
@ -51,6 +50,7 @@ mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
cache-enabled: true
|
||||
global-config:
|
||||
db-config:
|
||||
logic-delete-field: deleted_flag # 全局逻辑删除的实体字段名
|
||||
|
||||
Loading…
Reference in New Issue
Block a user