当前位置: 首页 > news >正文

惠州专业网站建设中国企业在线官网

惠州专业网站建设,中国企业在线官网,做北京塞车网站,服装公司网站源码Spring Boot 缓存 Cache 入门 1.概述 在系统访问量越来越大之后#xff0c;往往最先出现瓶颈的往往是数据库。而为了减少数据库的压力#xff0c;我们可以选择让产品砍掉消耗数据库性能的需求。 当然也可以引入缓存,在引入缓存之后#xff0c;我们的读操作的代码#xff…Spring Boot 缓存 Cache 入门 1.概述 在系统访问量越来越大之后往往最先出现瓶颈的往往是数据库。而为了减少数据库的压力我们可以选择让产品砍掉消耗数据库性能的需求。 当然也可以引入缓存,在引入缓存之后我们的读操作的代码往往代码如下 // UserService.javaAutowired private UserMapper userMapper; // 读取 DBAutowired private UserCacheDao userCacheDao; // 读取 Cachepublic UserDO getUser(Integer id) {// 从 Cache 中查询用户信息UserDO user userCacheDao.get(id);if (user ! null) {return user;}// 如果 Cache 查询不到从 DB 中读取user userMapper.selectById(id);if (user ! null) { // 非空则缓存到 Cache 中userCacheDao.put(user);}// 返回结果return user; }这段代码是比较常用的缓存策略俗称**“被动写”**。整体步骤如下 1首先从 Cache 中读取用户缓存。如果存在则直接返回。2然后从 DB 中读取用户数据。如果存在写入 Cache 中。3最后返回 DB 的查询结果。 Spring Cache 缓存让我们可以像使用 Transactional 声明式事务使用 Spring Cache 提供的 Cacheable 等注解 声明式缓存。而在实现原理上也是基于 Spring AOP 拦截实现缓存相关的操作。 下面我们使用 Spring Cache 将 #getUser(Integer id) 方法进行简化。代码如下 // UserService.java public UserDO getUser2(Integer id) {return userMapper.selectById(id); }// UserMapper.java Cacheable(value users, key #id) UserDO selectById(Integer id);在 UserService 的 #getUser2(Integer id) 方法上我们直接调用 UserMapper 从 DB 中查询数据。在 UserMapper 的 #selectById(Integer id) 方法上有 Cacheable 注解。Spring Cache 会拦截有 Cacheable 注解的方法实现“被动写”的逻辑。 2. 注解 在入门 Spring Cache 之前我们先了解下其提供的所有注解 CacheableCachePutCacheEvictCacheConfigCachingEnableCaching 2.1 Cacheable Cacheable 注解添加在方法上缓存方法的执行结果。执行过程如下 1首先判断方法执行结果的缓存。如果有则直接返回该缓存结果。2然后执行方法获得方法结果。3之后根据是否满足缓存的条件。如果满足则缓存方法结果到缓存。4最后返回方法结果。 Cacheable 注解的常用属性如下 cacheNames 属性缓存名。必填。[] 数组可以填写多个缓存名。values 属性和 cacheNames 属性相同是它的别名。key 属性缓存的 key 。允许空。 如果为空则默认方法的所有参数进行组合。如果非空则需要按照 SpEL(Spring Expression Language) 来配置。例如说Cacheable(value users, key #id) 使用方法参数 id 的值作为缓存的 key 。 condition 属性基于方法入参判断要缓存的条件。允许空。 如果为空则不进行入参的判断。如果非空则需要按照 SpEL(Spring Expression Language) 来配置。例如说Cacheable(condition#id 0) 需要传入的 id 大于零。 unless 属性基于方法返回判断不缓存的条件。允许空。 如果为空则不进行入参的判断。如果非空则需要按照 SpEL(Spring Expression Language) 来配置。例如说Cacheable(unless#result null) 如果返回结果为 null 则不进行缓存。要注意condition 和 unless 都是条件属性差别在于前者针对入参后者针对结果。 Cacheable 注解的不常用属性如下 keyGenerator 属性自定义 key 生成器 KeyGenerator Bean 的名字。允许空。如果设置则 key 失效。cacheManager 属性自定义缓存管理器 CacheManager Bean 的名字。允许空。一般不填写除非有多个 CacheManager Bean 的情况下。cacheResolver 属性自定义缓存解析器 CacheResolver Bean 的名字。允许空。sync 属性在获得不到缓存的情况下是否同步执行方法。 默认为 false 表示无需同步。如果设置为 true 则执行方法时会进行加锁保证同一时刻有且仅有一个方法在执行其它线程阻塞等待。通过这样的方式避免重复执行方法。注意该功能的实现需要参考第三方缓存的具体实现。 2.2 CachePut CachePut 注解添加在方法上缓存方法的执行结果。不同于 Cacheable 注解它的执行过程如下 1首先执行方法获得方法结果。也就是说无论是否有缓存都会执行方法。2然后根据是否满足缓存的条件。如果满足则缓存方法结果到缓存。3最后返回方法结果。 一般来说使用方式如下 Cacheable搭配读操作实现缓存的被动写。CachePut配置写操作实现缓存的主动写。 Cacheable 注解的属性和 Cacheable 注解的属性基本一致只少一个 sync 属性。 2.3 CacheEvict CacheEvict 注解添加在方法上删除缓存。 相比 CachePut 注解它额外多了两个属性 allEntries 属性是否删除缓存名( cacheNames )下所有 key 对应的缓存。默认为 false 只删除指定 key 的缓存。beforeInvocation 属性是否在方法执行前删除缓存。默认为 false 在方法执行后删除缓存。 2.4 Caching Caching 注解添加在方法上可以组合使用多个 Cacheable、CachePut、CacheEvict 注解。不太常用可以暂时忽略。 2.5 CacheConfig CacheConfig 注解添加在类上共享如下四个属性的配置 cacheNameskeyGeneratorcacheManagercacheResolver 2.6 EnableCaching EnableCaching 注解标记开启 Spring Cache 功能所以一定要添加。代码如下 // EnableCaching.javaboolean proxyTargetClass() default false;AdviceMode mode() default AdviceMode.PROXY;int order() default Ordered.LOWEST_PRECEDENCE;3. Spring Boot 集成 在 Spring Boot 里提供了 spring-boot-starter-cache 库实现 Spring Cache 的自动化配置通过 CacheAutoConfiguration 配置类。 在 Java 后端开发中常见的缓存工具和框架列举如下 本地缓存Guava LocalCache、Ehcache、Caffeine 。 Ehcache 的功能更加丰富Caffeine 的性能要比 Guava LocalCache 好。 分布式缓存Redis、Memcached、Tair 。 Redis 最为主流和常用。 4.Redis示例 4.1引入依赖 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- 实现对数据库连接池的自动化配置 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependencydependency !-- 本示例我们使用 MySQL --groupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!-- 实现对 MyBatis Plus 的自动化配置 --dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactId/dependency!-- 实现对 Caches 的自动化配置 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId/dependency!-- 实现对 Spring Data Redis 的自动化配置 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdexclusions!-- 去掉对 Lettuce 的依赖因为 Spring Boot 优先使用 Lettuce 作为 Redis 客户端 --exclusiongroupIdio.lettuce/groupIdartifactIdlettuce-core/artifactId/exclusion/exclusions/dependency!-- 引入 Jedis 的依赖这样 Spring Boot 实现对 Jedis 的自动化配置 --dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactId/dependency!--引入lombok--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency!-- 方便等会写单元测试 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesSpring Data 使用 Redis 作为缓存的方案的时候底层使用的是 Spring Data 提供的 RedisTemplate 所以我们引入 spring-boot-starter-data-redis 依赖实现对 RedisTemplate 的自动化配置。 4.2应用配置文件 spring:# datasource 数据源配置内容datasource:url: jdbc:mysql://127.0.0.1:3306/llp?useSSLfalseuseUnicodetruecharacterEncodingUTF-8driver-class-name: com.mysql.jdbc.Driverusername: rootpassword: root# 对应 RedisProperties 类redis:host: 127.0.0.1port: 6379password: # Redis 服务器密码默认为空。生产中一定要设置 Redis 密码database: 0 # Redis 数据库号默认为 0 。timeout: 0 # Redis 连接超时时间单位毫秒。# 对应 RedisProperties.Jedis 内部类jedis:pool:max-active: 8 # 连接池最大连接数默认为 8 。使用负数表示没有限制。max-idle: 8 # 默认连接数最小空闲的连接数默认为 8 。使用负数表示没有限制。min-idle: 0 # 默认连接池最小空闲的连接数默认为 0 。允许设置 0 和 正数。max-wait: -1 # 连接池最大阻塞等待时间单位毫秒。默认为 -1 表示不限制。# cache 缓存配置内容cache:type: redis# mybatis-plus 配置内容 mybatis-plus:configuration:map-underscore-to-camel-case: true # 虽然默认为 true 但是还是显示去指定下。global-config:db-config:id-type: auto # ID 主键自增logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)mapper-locations: classpath*:mapper/*.xmltype-aliases-package: com.llp.cache.dataobject# logging logging:level:# dao 开启 debug 模式 mybatis 输入 sqlcom:llp:cache:mapper: debug spring.datasource 配置项下设置数据源相关的配置。spring.cache配置项下设置 Cache 相关的配置。 type 属性设置 Cache 使用方案为 Redis 。 spring.redis 配置项下设置 Spring Data Redis 相关的配置。如果没有使用过 Spring Data Redis 的胖友不用慌照着改就好。mybatis-plus 配置项下设置 MyBatis-Plus 相关的配置。logging 配置项设置打印 SQL 日志方便我们查看是否读取了 DB 。 4.3 Application启动类 EnableCaching //开启缓存支持 MapperScan(basePackages {com.llp.cache.mapper}) SpringBootApplication public class CacheApplication {public static void main(String[] args) {SpringApplication.run(CacheApplication.class, args);} }4.4UserDO TableName(value users) Data public class UserDO {/*** 用户编号*/private Integer id;/*** 账号*/private String username;/*** 密码明文** ps生产环境下千万不要明文噢*/private String password;/*** 创建时间*/private Date createTime;/*** 是否删除*/TableLogicprivate Integer deleted;}4.5UserMapper import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.llp.cache.dataobject.UserDO; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Repository;Repository //统一配置该 UserMapper 使用的缓存名为 users ,类的方法上使用cacheNames将不会生效 CacheConfig(cacheNames users) public interface UserMapper extends BaseMapperUserDO {/*** Cacheable 注解添加在方法上缓存方法的执行结果。执行过程如下** 1首先判断方法执行结果的缓存。如果有则直接返回该缓存结果。* 2然后执行方法获得方法结果。* 3之后根据是否满足缓存的条件。如果满足则缓存方法结果到缓存。* 4最后返回方法结果。* 只有一个参数: #a0 或 #p0* param id* return*/Cacheable(key #a0)UserDO selectById(Integer id);/*** CachePut 注解添加在方法上缓存方法的执行结果。不同于 Cacheable 注解它的执行过程如下** 1首先执行方法获得方法结果。也就是说无论是否有缓存都会执行方法。* 2然后根据是否满足缓存的条件。如果满足则缓存方法结果到缓存。* 3最后返回方法结果。* param user* return*/CachePut(key #user.id)default UserDO insert0(UserDO user) {// 插入记录this.insert(user);// 返回用户return user;}//CacheEvict清理掉缓存,常用于修改和删除CacheEvict(key #p0)int deleteById(Integer id);}4.6UserMapperTest RunWith(SpringRunner.class) SpringBootTest(classes CacheApplication.class) public class UserMapperTest {private static final String CACHE_NAME_USER users;Autowiredprivate UserMapper userMapper;Autowiredprivate CacheManager cacheManager;Testpublic void testCacheManager() {System.out.println(cacheManager);}Testpublic void testSelectById() {// 这里胖友事先插入一条 id 1 的记录。Integer id 1;// 1.1 查询 id 1 的记录UserDO user userMapper.selectById(id);System.out.println(user user);// 1.2 判断缓存中是不是存在Assert.assertNotNull(缓存为空, cacheManager.getCache(CACHE_NAME_USER).get(user.getId(), UserDO.class));// 2 查询 id 1 的记录user userMapper.selectById(id);System.out.println(user user);}Testpublic void testInsert() {// 1 插入记录UserDO user new UserDO();user.setUsername(UUID.randomUUID().toString()); // 随机账号因为唯一索引user.setPassword(llp);user.setCreateTime(new Date());user.setDeleted(0);userMapper.insert0(user);// 2 判断缓存中是不是存在Assert.assertNotNull(缓存为空, cacheManager.getCache(CACHE_NAME_USER).get(user.getId(), UserDO.class));}Testpublic void testDeleteById() {// 1 插入记录为了让缓存里有记录UserDO user new UserDO();user.setUsername(UUID.randomUUID().toString()); // 随机账号因为唯一索引user.setPassword(llp);user.setCreateTime(new Date());user.setDeleted(0);userMapper.insert0(user);// 2 判断缓存中是不是存在Assert.assertNotNull(缓存为空, cacheManager.getCache(CACHE_NAME_USER).get(user.getId(), UserDO.class));// 3.1 删除记录为了让缓存被删除userMapper.deleteById(user.getId());// 3.2 判断缓存中是不是存在Assert.assertNull(缓存不为空, cacheManager.getCache(CACHE_NAME_USER).get(user.getId(), UserDO.class));}}4.7过期时间 在 Spring Data 使用 Redis 作为缓存方案时默认情况下是永不过期的。 127.0.0.1:6379 ttl users::1 (integer) -1在 Redis 命令行中我们可以看到 users::1 的过期时间为 -1 永不过期。 虽然说我们可以通 spring.cache.redis.time-to-live 配置项设置过期时间。但是它是全局的统一的。这样在实际使用时是无法满足我们希望不同的缓存使用不同的过期时间。 spring:# datasource 数据源配置内容datasource:url: jdbc:mysql://127.0.0.1:3306/llp?useSSLfalseuseUnicodetruecharacterEncodingUTF-8driver-class-name: com.mysql.jdbc.Driverusername: rootpassword: root# 对应 RedisProperties 类redis:host: 127.0.0.1port: 6379password: # Redis 服务器密码默认为空。生产中一定要设置 Redis 密码database: 0 # Redis 数据库号默认为 0 。timeout: 0 # Redis 连接超时时间单位毫秒。cache:type: redisredis:time-to-live: 1h4.8 Cacheable(Redis)缓存失效时间解决方案 问题 Cacheable注解不支持配置过期时间所有需要通过配置CacheManneg来配置默认的过期时间和针对每个类或者是方法进行缓存失效时间配置。 解决 可以采用如下的配置信息来解决的设置失效时间问题 配置信息 import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cache.CacheManager; import org.springframework.cache.interceptor.KeyGenerator; 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.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext;import java.lang.reflect.Method; import java.time.Duration; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors;Configuration public class CacheConfig {Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),this.getRedisCacheConfigurationWithTtl(30 * 60), // 默认策略未配置的 key 会使用这个this.getRedisCacheConfigurationMap() // 指定 key 策略);}private MapString, RedisCacheConfiguration getRedisCacheConfigurationMap() {MapString, RedisCacheConfiguration redisCacheConfigurationMap new HashMap();//SsoCache和BasicDataCache进行过期时间配置redisCacheConfigurationMap.put(SsoCache, this.getRedisCacheConfigurationWithTtl(24 * 60 * 60));redisCacheConfigurationMap.put(BasicDataCache, this.getRedisCacheConfigurationWithTtl(30 * 60));return redisCacheConfigurationMap;}private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);RedisCacheConfiguration redisCacheConfiguration RedisCacheConfiguration.defaultCacheConfig();redisCacheConfiguration redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofSeconds(seconds));return redisCacheConfiguration;}//指定缓存key的生成方式Beanpublic KeyGenerator wiselyKeyGenerator() {KeyGenerator keyGenerator new KeyGenerator() {Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder sb new StringBuilder();sb.append(target.getClass().getName());sb.append(. method.getName());if (params null || params.length 0 || params[0] null) {return null;}String join String.join(, Arrays.stream(params).map(Object::toString).collect(Collectors.toList()));String format String.format(%s{%s}, sb.toString(), join);//log.info(缓存key format);return format;}};return keyGenerator;}} 使用方式 Repository //统一配置该 UserMapper 使用的缓存名为 users ,方法中使用了cacheNames,则类的方法上使用cacheNames将不会生效 CacheConfig(cacheNames users) public class SsoCache{Cacheable(value BasicDataCache,keyGenerator wiselyKeyGenerator)UserDO selectById(Integer id);//二者选其一,可以使用value上的信息来替换类上cacheNames的信息Cacheable(value SsoCache,keyGenerator wiselyKeyGenerator)UserDO selectById(Integer id); }BasicDataCache SsoCache
http://www.hkea.cn/news/14539456/

相关文章:

  • 梅州住房和建设局网站长沙抖音seo公司地址
  • 网站制作公司咨询工作内容wordpress get_posts category
  • 企业网站 html模板网站服务器宽带
  • 湛江网站如何制作南宁建站服务公司
  • 个人网站建设视频教学福州mip网站建设
  • 网站开发前景网络项目一天赚500
  • 做网站应该学什么语言嵌入式软件能干一辈子
  • 苍山网站建设西安网页设计培训班价格
  • 贵阳网站建设托管wordpress主题繁体
  • 图片网站模版开发一个app成本
  • 旅游网站开发的重要性凡客建站
  • 如何在外管局网站上做a合同网站怎么做会让神马搜索到
  • 学做衣服网 缤纷网站重庆网站推广哪家服务好
  • 网站建设 58同城深圳建筑设计院招聘信息
  • 怎么刷网站权重网站收录差
  • 几大门户网站宁波网络推广平台推荐
  • 泰安专业网站开发公司企业信息查询app哪个最好
  • 源汇区建设局网站装修公司网站怎么做
  • 网站优化公司大家好太原定制网站制作流程
  • 济南会做网站的公司优化电脑的软件有哪些
  • cnzz网站建设教学wordpress dux主题首页排序
  • 网站关键词放哪河南省住房和城乡建设厅网站主页
  • 新手怎么建立网站哪家网站设计公司好
  • dedecms做网站教程中国建设银行官网电脑版
  • 企业查询官方网站网站 关键字
  • 北京网页网站设计制作网站团队人员
  • 中国建设银行老版本下载官方网站12306网站开发多少钱
  • 无锡 网站开发对外网站ipv6建设方案模板
  • 网站建设的条件做海报素材的网站
  • 微信网站的结构开源html5 网站模板