辽宁省建设厅科技中心网站,中国廉洁建设网是什么正规网站吗,东莞网站建设推广品众,小红门网站建设环境准备
注解
EnableCaching CacheConfig CacheConfig 提供了一种在类级别共享公共缓存相关设置的机制。 | 参数 | 作用 | | | — | — | — | | cacheNames | 使用在类上的默认缓存名称 | | | keyGenerator | 用于类的默认KeyGenerator的bean名称 | | | cacheManager | 自定…环境准备
注解
EnableCaching CacheConfig CacheConfig 提供了一种在类级别共享公共缓存相关设置的机制。 | 参数 | 作用 | | | — | — | — | | cacheNames | 使用在类上的默认缓存名称 | | | keyGenerator | 用于类的默认KeyGenerator的bean名称 | | | cacheManager | 自定义CacheManager的bean名称如果尚未设置则可以用于创建默认CacheResolver | | | cacheResolver | 要使用的自定义CacheResolver的bean名称 | |
Cacheable Cacheable 可以标记在一个方法上也可以标记在类上当标记在类上时当前类的所有方法都支持缓存当注解的方法被调用时如果缓存中有值则直接返回缓存中的数据 参数作用examplecacheNames / value缓存的空间名称这两个配置只能二选一key / keyGenerator缓存的key同一个空间名称value下的key唯一可以通过SpEL 表达式编写指定这个key的值或者通过keyGenerator生成这两个配置只能二选一cacheManager自定义CacheManager的bean名称如果尚未设置则可以用于创建默认CacheResolvercacheResolver要使用的自定义CacheResolver的bean名称condition缓存的条件默认为true使用 SpEL 编写返回true或者false只有为true才进行缓存。为true时如果缓存有值则不执行方法如果缓存没值则执行方法并将结果保存到缓存。为false时不执行缓存每次都执行方法。unless函数返回值符合条件的不缓存、只缓存其余不符合条件的。可以使用 SpEL 编写方法参数可以通过索引访问例如第二个参数可以通过#root.args[1]、#p1或#a1访问sync是否使用异步模式。默认是方法执行完以同步的方式将方法返回的结果存在缓存中 Cacheable(cacheNames spaceUserPre, key #redisSyc.name,condition true,unless #result?.resultnull)public RedisSyc select(RedisSyc redisSyc){RedisSyc select redisAnnoMapper.select(redisSyc);return select;}CachePut CachePut 可以标记在一个方法上也可以标记在类上。使用 CachePut 标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果而是每次都会执行该方法然后将执行结果以键值对的形式存入指定的缓存中 | 参数 | 作用 | | | — | — | — | | cacheNames / value | 缓存的空间名称这两个配置只能二选一 | | | key / keyGenerator | 缓存的key同一个空间名称value下的key唯一可以通过SpEL 表达式编写指定这个key的值或者通过keyGenerator生成这两个配置只能二选一 | | | cacheManager | 自定义CacheManager的bean名称如果尚未设置则可以用于创建默认CacheResolver | | | cacheResolver | 要使用的自定义CacheResolver的bean名称 | | | condition | 缓存的条件默认为true使用 SpEL 编写返回true或者false只有为true才进行缓存。为true时如果缓存有值则不执行方法如果缓存没值则执行方法并将结果保存到缓存。为false时不执行缓存每次都执行方法。 | | | unless | 函数返回值符合条件的不缓存、只缓存其余不符合条件的。可以使用 SpEL 编写方法参数可以通过索引访问例如第二个参数可以通过#root.args[1]、#p1或#a1访问 | | CachePut(cacheNames spaceUserPre, key #redisSyc.name,condition true,unless #resultnull )public RedisSyc add(RedisSyc redisSyc){redisAnnoMapper.add(redisSyc);log.info(添加成功:{},new Gson().toJson(redisSyc));return redisSyc;}CacheEvict CacheEvict 可以标记在一个方法上也可以标记在类上用来清除缓存元素的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。 | 参数 | 作用 | | | — | — | — | | cacheNames / value | 缓存的空间名称这两个配置只能二选一 | | | key / keyGenerator | 缓存的key同一个空间名称value下的key唯一可以通过SpEL 表达式编写指定这个key的值或者通过keyGenerator生成这两个配置只能二选一 | | | cacheManager | 自定义CacheManager的bean名称如果尚未设置则可以用于创建默认CacheResolver | | | cacheResolver | 要使用的自定义CacheResolver的bean名称 | | | condition | 缓存的条件默认为true使用 SpEL 编写返回true或者false只有为true才进行缓存。为true时如果缓存有值则不执行方法如果缓存没值则执行方法并将结果保存到缓存。为false时不执行缓存每次都执行方法。 | | | allEntries | 为true时表示清除cacheNames或value空间名里的所有的数据 | | | beforeInvocation | 为false时缓存的清除是否再方法之前执行,默认代表缓存清除操作是在方法执行后执行如果出现异常缓存就不会清除;为true时代表清除缓存操作是在方法运行之前执行无论方法是否出现异常缓存都清除 | | CacheEvict(cacheNames spaceUserPre, key #redisSyc.name,condition true,allEntries true,beforeInvocation true )public void delete(RedisSyc redisSyc){redisAnnoMapper.delete(redisSyc);}Caching Caching 多个缓存注解不同或相同类型的组注解。 | 参数 | 作用 | | | — | — | — | | cacheNames / value | 缓存的空间名称这两个配置只能二选一 | | | key / keyGenerator | 缓存的key同一个空间名称value下的key唯一可以通过SpEL 表达式编写指定这个key的值或者通过keyGenerator生成这两个配置只能二选一 | | | cacheManager | 自定义CacheManager的bean名称如果尚未设置则可以用于创建默认CacheResolver | | | cacheResolver | 要使用的自定义CacheResolver的bean名称 | | | condition | 缓存的条件默认为true使用 SpEL 编写返回true或者false只有为true才进行缓存。为true时如果缓存有值则不执行方法如果缓存没值则执行方法并将结果保存到缓存。为false时不执行缓存每次都执行方法。 | | | allEntries | 为true时表示清除cacheNames或value空间名里的所有的数据 | | | beforeInvocation | 为false时缓存的清除是否再方法之前执行,默认代表缓存清除操作是在方法执行后执行如果出现异常缓存就不会清除;为true时代表清除缓存操作是在方法运行之前执行无论方法是否出现异常缓存都清除 | |
spEL 编写 key springboot集成
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.17/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.redis/groupIdartifactIdredis01/artifactIdversion0.0.1-SNAPSHOT/versionnameredis01/namedescriptionredis01/descriptionpropertiesjava.version8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.0.0/version/dependency!--alibaba的druid数据库连接池 德鲁伊--dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion1.1.10/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependency!--Mybatis整合springboot的起步依赖--dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.0.0/version/dependency!--【数据库】数据库连接池--dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.2.11/version/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!--jedis--dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion4.3.1/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/plugin/pluginsresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.xml/include/includes/resource/resources/build/project
#连接数据源
spring.datasource.druid.usernameroot
spring.datasource.druid.passwordxgm2023..
spring.datasource.druid.urljdbc:mysql://172.16.204.51:3306/redis?serverTimezoneGMT%2B8
spring.datasource.druid.driver-class-namecom.mysql.cj.jdbc.Driver
spring.datasource.druid.initial-size5##指定缓存类型redis
#spring.cache.typeredis
##一个小时以毫秒为单位
#spring.cache.redis.time-to-live3600000
##给缓存的建都起一个前缀。 如果指定了前缀就用我们指定的如果没有就默认使用缓存的名字作为前缀,一般不指定
#spring.cache.redis.key-prefixCACHE_
##指定是否使用前缀
#spring.cache.redis.use-key-prefixtrue
##是否缓存空值防止缓存穿透
#spring.cache.redis.cache-null-valuestrue#redis
spring.redis.host172.16.204.51
spring.redis.port6379
spring.redis.password123456
spring.redis.database1# mybatis配置
mybatis:
check-config-location: true
# mybatis框架配置文件对mybatis的生命周期起作用
config-location: classpath:mybatis/mybatis-config.xml
# 配置xml路径
mapper-locations: classpath:mybatis/mapper/*Mapper.xml
# 配置model包路径
type-aliases-package: com.redis.redis01.bean.*#日志
logging.level.rootdebug
logging.level.io.lettuce.coredebug
logging.level.org.springframework.data.redisdebug
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configuration PUBLIC-//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd
configurationsettings!-- 全局的映射器启用或禁用缓存。 --setting namecacheEnabled valuetrue/!-- 全局启用或禁用延迟加载 --setting namelazyLoadingEnabled valuetrue/!-- 允许或不允许多种结果集从一个单独的语句中返回 --setting namemultipleResultSetsEnabled valuetrue/!-- 使用列标签代替列名 --setting nameuseColumnLabel valuetrue/!-- 允许JDBC支持生成的键 --setting nameuseGeneratedKeys valuefalse/!-- 配置默认的执行器 --setting namedefaultExecutorType valueSIMPLE/!-- 设置超时时间 --setting namedefaultStatementTimeout value60/!-- 设置驼峰标识 --setting namemapUnderscoreToCamelCase valuetrue//settingsplugins!-- 分页插件 --plugin interceptorcom.github.pagehelper.PageInterceptor //plugins
/configuration
package com.redis.redis01.conf;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import com.redis.redis01.bean.CacheConstant;
import lombok.extern.slf4j.Slf4j;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.BatchStrategies;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.*;import javax.annotation.Resource;
import java.time.Duration;import static java.util.Collections.singletonMap;/*** 开启缓存支持* author zyf* Return:*/
Slf4j
//创建redis配置类一定要注意打上EnableCaching注解否则spring自带的缓存注解功能将不会自动启用
EnableCaching
Configuration
public class RedisConfig extends CachingConfigurerSupport {Resourceprivate LettuceConnectionFactory lettuceConnectionFactory;// /**
// * description 自定义的缓存key的生成策略 若想使用这个key
// * 只需要讲注解上keyGenerator的值设置为keyGenerator即可/br
// * return 自定义策略生成的key
// */
// Override
// Bean
// public KeyGenerator keyGenerator() {
// return new KeyGenerator() {
// Override
// public Object generate(Object target, Method method, Object... params) {
// StringBuilder sb new StringBuilder();
// sb.append(target.getClass().getName());
// sb.append(method.getDeclaringClass().getName());
// Arrays.stream(params).map(Object::toString).forEach(sb::append);
// return sb.toString();
// }
// };
// }/*** RedisTemplate配置* param lettuceConnectionFactory* return*/Beanpublic RedisTemplateString, Object redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {log.debug( --- redis config init --- );Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer jacksonSerializer();RedisTemplateString, Object redisTemplate new RedisTemplateString, Object();redisTemplate.setConnectionFactory(lettuceConnectionFactory);RedisSerializerString stringSerializer new StringRedisSerializer();// key序列化redisTemplate.setKeySerializer(stringSerializer);// value序列化redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// Hash key序列化redisTemplate.setHashKeySerializer(stringSerializer);// Hash value序列化redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}/*** 缓存配置管理器** param factory* return*/Beanpublic CacheManager cacheManager(LettuceConnectionFactory factory) {Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer jacksonSerializer();// 配置序列化解决乱码的问题,并且配置缓存默认有效期 6小时RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(6));RedisCacheConfiguration redisCacheConfiguration config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));//.disableCachingNullValues();// 以锁写入的方式创建RedisCacheWriter对象//update-begin-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*RedisCacheWriter writer new MyRedisCacheWriter(factory, Duration.ofMillis(50L));//RedisCacheWriter.lockingRedisCacheWriter(factory);// 创建默认缓存配置对象/* 默认配置设置缓存有效期 1小时*///RedisCacheConfiguration defaultCacheConfig RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));/* 自定义配置test:demo 的超时时间为 5分钟*/RedisCacheManager cacheManager RedisCacheManager.builder(writer).cacheDefaults(redisCacheConfiguration).withInitialCacheConfigurations(singletonMap(CacheConstant.SYS_DICT_TABLE_CACHE,RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)).disableCachingNullValues().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)))).withInitialCacheConfigurations(singletonMap(CacheConstant.TEST_DEMO_CACHE, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).disableCachingNullValues())).transactionAware().build();// RedisCacheManager cacheManager
// RedisCacheManager
// .builder(RedisCacheWriter.lockingRedisCacheWriter
// (factory, BatchStrategies.scan(1000))).cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(Long.valueOf(10))).disableCachingNullValues())
// .transactionAware()
// .build();//update-end-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*return cacheManager;}private Jackson2JsonRedisSerializer jacksonSerializer() {Jackson2JsonRedisSerializer jackson2JsonRedisSerializer new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);return jackson2JsonRedisSerializer;}}package com.redis.redis01.conf;import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.data.redis.cache.CacheStatistics;
import org.springframework.data.redis.cache.CacheStatisticsCollector;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;/*** 该类参照 DefaultRedisCacheWriter 重写了 remove 方法实现通配符*删除,解决生产环境禁用kyes*后。CacheEvict报错问题*/
Slf4j
public class MyRedisCacheWriter implements RedisCacheWriter {private final RedisConnectionFactory connectionFactory;private final Duration sleepTime;public MyRedisCacheWriter(RedisConnectionFactory connectionFactory) {this(connectionFactory, Duration.ZERO);}public MyRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {Assert.notNull(connectionFactory, ConnectionFactory must not be null!);Assert.notNull(sleepTime, SleepTime must not be null!);this.connectionFactory connectionFactory;this.sleepTime sleepTime;}public void put(String name, byte[] key, byte[] value, Nullable Duration ttl) {Assert.notNull(name, Name must not be null!);Assert.notNull(key, Key must not be null!);Assert.notNull(value, Value must not be null!);this.execute(name, (connection) - {if (shouldExpireWithin(ttl)) {connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());} else {connection.set(key, value);}return OK;});}public byte[] get(String name, byte[] key) {Assert.notNull(name, Name must not be null!);Assert.notNull(key, Key must not be null!);return this.execute(name, (connection) - {return connection.get(key);});}public byte[] putIfAbsent(String name, byte[] key, byte[] value, Nullable Duration ttl) {Assert.notNull(name, Name must not be null!);Assert.notNull(key, Key must not be null!);Assert.notNull(value, Value must not be null!);return this.execute(name, (connection) - {if (this.isLockingCacheWriter()) {this.doLock(name, connection);}Object var7;try {boolean put;if (shouldExpireWithin(ttl)) {put connection.set(key, value, Expiration.from(ttl), SetOption.ifAbsent());} else {put connection.setNX(key, value);}if (!put) {byte[] var11 connection.get(key);return var11;}var7 null;} finally {if (this.isLockingCacheWriter()) {this.doUnlock(name, connection);}}return (byte[])var7;});}public void remove(String name, byte[] key) {Assert.notNull(name, Name must not be null!);Assert.notNull(key, Key must not be null!);String keyString new String(key);log.debug(redis remove key: keyString);if(keyString!null keyString.endsWith(*)){execute(name, connection - {// 获取某个前缀所拥有的所有的键某个前缀开头后面肯定是*Setbyte[] keys connection.keys(key);int delNum 0;for (byte[] keyByte : keys) {delNum connection.del(keyByte);}return delNum;});}else{this.execute(name, (connection) - {return connection.del(new byte[][]{key});});}}public void clean(String name, byte[] pattern) {Assert.notNull(name, Name must not be null!);Assert.notNull(pattern, Pattern must not be null!);this.execute(name, (connection) - {boolean wasLocked false;try {if (this.isLockingCacheWriter()) {this.doLock(name, connection);wasLocked true;}// byte[][] keys (byte[][])((Set)Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())).toArray(new byte[0][]);// 使用scan命令代替原本的keys命令搜索keyfinal Cursorbyte[] cursor connection.scan(ScanOptions.scanOptions().count(100).match(pattern).build());Setbyte[] byteSet new HashSet();while (cursor.hasNext()) {byteSet.add(cursor.next());}byte[][] keys byteSet.toArray(new byte[0][]);if (keys.length 0) {connection.del(keys);}} finally {if (wasLocked this.isLockingCacheWriter()) {this.doUnlock(name, connection);}}return OK;});}Overridepublic void clearStatistics(String name) {}Overridepublic RedisCacheWriter withStatisticsCollector(CacheStatisticsCollector cacheStatisticsCollector) {return null;}void lock(String name) {this.execute(name, (connection) - {return this.doLock(name, connection);});}void unlock(String name) {this.executeLockFree((connection) - {this.doUnlock(name, connection);});}private Boolean doLock(String name, RedisConnection connection) {return connection.setNX(createCacheLockKey(name), new byte[0]);}private Long doUnlock(String name, RedisConnection connection) {return connection.del(new byte[][]{createCacheLockKey(name)});}boolean doCheckLock(String name, RedisConnection connection) {return connection.exists(createCacheLockKey(name));}private boolean isLockingCacheWriter() {return !this.sleepTime.isZero() !this.sleepTime.isNegative();}private T T execute(String name, FunctionRedisConnection, T callback) {RedisConnection connection this.connectionFactory.getConnection();try {this.checkAndPotentiallyWaitUntilUnlocked(name, connection);return callback.apply(connection);} finally {connection.close();}}private void executeLockFree(ConsumerRedisConnection callback) {RedisConnection connection this.connectionFactory.getConnection();try {callback.accept(connection);} finally {connection.close();}}private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {if (this.isLockingCacheWriter()) {try {while(this.doCheckLock(name, connection)) {Thread.sleep(this.sleepTime.toMillis());}} catch (InterruptedException var4) {Thread.currentThread().interrupt();throw new PessimisticLockingFailureException(String.format(Interrupted while waiting to unlock cache %s, name), var4);}}}private static boolean shouldExpireWithin(Nullable Duration ttl) {return ttl ! null !ttl.isZero() !ttl.isNegative();}private static byte[] createCacheLockKey(String name) {return (name ~lock).getBytes(StandardCharsets.UTF_8);}Overridepublic CacheStatistics getCacheStatistics(String cacheName) {return null;}
}