Spring Boot Redis 缓存完全指南

1. 项目依赖配置

1.1 Maven依赖

<dependencies><!-- Spring Boot Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Spring Boot Cache --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- Apache Commons Pool2 - Redis连接池需要 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- FastJson - 用于Redis序列化 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency><!-- Lombok - 简化代码 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

1.2 环境配置文件

application.yml 不同环境配置示例:

spring:# 开发环境配置profiles: devredis:host: localhostport: 6379password: database: 0timeout: 10000mslettuce:pool:max-active: 8max-wait: -1msmax-idle: 8min-idle: 0shutdown-timeout: 100ms---
# 生产环境配置
spring:profiles: prodredis:host: redis.prod.company.comport: 6379password: ${REDIS_PASSWORD}  # 使用环境变量database: 0timeout: 10000mslettuce:pool:max-active: 32max-wait: 3000msmax-idle: 16min-idle: 8shutdown-timeout: 100ms

2. Redis配置类详解

2.1 基础配置类

@Configuration
@EnableCaching
@Slf4j
public class RedisConfiguration {/*** Redis连接工厂配置*/@Beanpublic RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {LettuceConnectionFactory factory = new LettuceConnectionFactory();factory.setHostName(redisProperties.getHost());factory.setPort(redisProperties.getPort());factory.setPassword(redisProperties.getPassword());factory.setDatabase(redisProperties.getDatabase());return factory;}/*** FastJson序列化器配置*/@Beanpublic FastJsonRedisSerializer<Object> fastJsonRedisSerializer() {FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);FastJsonConfig config = new FastJsonConfig();// 序列化规则配置config.setSerializerFeatures(SerializerFeature.WriteClassName,SerializerFeature.WriteMapNullValue,SerializerFeature.PrettyFormat,SerializerFeature.WriteNullListAsEmpty,SerializerFeature.WriteNullStringAsEmpty);serializer.setFastJsonConfig(config);return serializer;}
}

2.2 缓存管理器配置

@Configuration
public class CacheManagerConfig {@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, FastJsonRedisSerializer<Object> fastJsonRedisSerializer) {// 默认配置RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30))  // 默认过期时间.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).disableCachingNullValues();// 特定缓存空间配置Map<String, RedisCacheConfiguration> configMap = new HashMap<>();// 短期缓存配置 - 适用于频繁更新的数据configMap.put("shortCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).disableCachingNullValues());// 长期缓存配置 - 适用于不经常更新的数据configMap.put("longCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(12)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).disableCachingNullValues());// 永久缓存配置 - 适用于基础数据configMap.put("permanentCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ZERO)  // 永不过期.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).disableCachingNullValues());return RedisCacheManager.builder(connectionFactory).cacheDefaults(defaultConfig).withInitialCacheConfigurations(configMap).build();}
}

3. 缓存注解详细使用指南

3.1 @Cacheable 详解

public class CacheableExample {/*** 基本使用* value: 缓存空间名称* key: 缓存键,使用SpEL表达式* condition: 缓存条件* unless: 否定缓存条件*/@Cacheable(value = "userCache",key = "#id",condition = "#id != null",unless = "#result == null")public User getUser(Long id) {return userMapper.selectById(id);}/*** 复杂key示例* 组合多个参数作为key*/@Cacheable(value = "userCache",key = "#root.targetClass.simpleName + ':' + #name + ':' + #age")public List<User> getUsersByNameAndAge(String name, Integer age) {return userMapper.findByNameAndAge(name, age);}/*** 多缓存空间示例*/@Cacheable(cacheNames = {"shortCache", "backupCache"})public User getUserWithMultiCache(Long id) {return userMapper.selectById(id);}
}

3.2 @CachePut 详解

public class CachePutExample {/*** 更新缓存示例* 总是执行方法,并将结果更新到缓存*/@CachePut(value = "userCache",key = "#user.id",condition = "#user.age > 18")public User updateUser(User user) {userMapper.updateById(user);return user;}/*** 批量更新缓存示例*/@CachePut(value = "userCache",key = "#user.id + ':' + #user.version")public List<User> batchUpdateUsers(List<User> users) {userMapper.batchUpdate(users);return users;}
}

3.3 @CacheEvict 详解

public class CacheEvictExample {/*** 删除指定缓存*/@CacheEvict(value = "userCache",key = "#id")public void deleteUser(Long id) {userMapper.deleteById(id);}/*** 批量删除缓存* allEntries = true 表示清除所有缓存* beforeInvocation = true 表示在方法执行前清除缓存*/@CacheEvict(value = "userCache",allEntries = true,beforeInvocation = true)public void clearAllUserCache() {log.info("清除所有用户缓存");}/*** 多缓存空间清除*/@Caching(evict = {@CacheEvict(value = "userCache", key = "#user.id"),@CacheEvict(value = "roleCache", key = "#user.roleId"),@CacheEvict(value = "permissionCache", key = "#user.id")})public void deleteUserAndRelatedCache(User user) {userMapper.deleteById(user.getId());}
}

4. 实战场景示例

4.1 统计数据缓存

@Service
@Slf4j
public class StatisticsServiceImpl implements StatisticsService {/*** 政治面貌统计* 使用短期缓存,因为统计数据会定期更新*/@Cacheable(value = "statisticsCache",key = "'political_stats_' + #region",unless = "#result == null || #result.isEmpty()")public Map<String, Object> getPoliticalStats(String region) {log.info("计算{}地区政治面貌统计数据", region);return statisticsMapper.calculatePoliticalStats(region);}/*** 定时更新缓存*/@Scheduled(cron = "0 0 1 * * ?")  // 每天凌晨1点执行@CacheEvict(value = "statisticsCache", allEntries = true)public void refreshStatisticsCache() {log.info("刷新统计数据缓存");}
}

4.2 多级缓存示例

@Service
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 多级缓存实现* 1. 先查本地缓存* 2. 再查Redis缓存* 3. 最后查数据库*/@Cacheable(value = "userCache",key = "#id",unless = "#result == null")public User getUserWithMultiLevelCache(Long id) {// 1. 查询本地缓存(使用Caffeine实现)User user = localCache.getIfPresent(id);if (user != null) {log.debug("从本地缓存获取用户: {}", id);return user;}// 2. 查询Redis缓存String redisKey = "user:" + id;user = (User) redisTemplate.opsForValue().get(redisKey);if (user != null) {log.debug("从Redis缓存获取用户: {}", id);// 放入本地缓存localCache.put(id, user);return user;}// 3. 查询数据库user = userMapper.selectById(id);if (user != null) {log.debug("从数据库获取用户: {}", id);// 放入本地缓存localCache.put(id, user);// 放入Redis缓存redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES);}return user;}
}

4.3 分布式锁与缓存结合

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 使用分布式锁防止缓存击穿*/@Cacheable(value = "orderCache",key = "#orderId",unless = "#result == null")public Order getOrderWithLock(String orderId) {String lockKey = "lock:order:" + orderId;boolean locked = false;try {// 尝试获取分布式锁locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "LOCKED", 10, TimeUnit.SECONDS);if (!locked) {// 未获取到锁,等待后重试Thread.sleep(100);return getOrderWithLock(orderId);}// 获取到锁,执行业务逻辑Order order = orderMapper.selectById(orderId);if (order != null) {// 添加缓存redisTemplate.opsForValue().set("order:" + orderId, order, 30, TimeUnit.MINUTES);}return order;} catch (InterruptedException e) {log.error("获取订单信息异常", e);Thread.currentThread().interrupt();return null;} finally {// 释放锁if (locked) {redisTemplate.delete(lockKey);}}}
}

5. 缓存监控与维护

5.1 缓存监控配置

@Configuration
public class CacheMonitorConfig {@Beanpublic CacheMetricsCollector cacheMetricsCollector(CacheManager cacheManager) {CacheMetricsCollector collector = new CacheMetricsCollector();// 注册缓存指标collector.bindCacheManager(cacheManager);return collector;}
}

5.2 自定义缓存监听器

@Component
public class CustomCacheEventListener extends CacheEventListenerAdapter {@Overridepublic void onEvent(CacheEvent event) {log.info("Cache event {} for key {} in cache {}", event.getType(), event.getKey(), event.getCache().getName());}
}

5.3 缓存统计

@Component
@Slf4j
public class CacheStats {@Autowiredprivate CacheManager cacheManager;/*** 收集缓存统计信息*/@Scheduled(fixedRate = 300000) // 每5分钟执行一次public void collectCacheStats() {Map<String, Map<String, Object>> stats = new HashMap<>();cacheManager.getCacheNames().forEach(cacheName -> {Cache cache = cacheManager.getCache(cacheName);if (cache instanceof RedisCache) {RedisCache redisCache = (RedisCache) cache;Map<String, Object> cacheStats = new HashMap<>();cacheStats.put("size", redisCache.estimatedSize());cacheStats.put("hitCount", redisCache.getStats().getHitCount());cacheStats.put("missCount", redisCache.getStats().getMissCount());stats.put(cacheName, cacheStats);}});log.info("Cache statistics: {}", stats);}
}

6. 最佳实践与注意事项

6.1 缓存键设计规范

public class CacheKeyConstants {// 使用常量定义缓存键前缀public static final String USER_CACHE_PREFIX = "user:";public static final String ORDER_CACHE_PREFIX = "order:";public static final String PRODUCT_CACHE_PREFIX = "product:";// 组合缓存键public static String getUserCacheKey(Long userId) {return USER_CACHE_PREFIX + userId;}public static String getOrderCacheKey(String orderId, String type) {return String.format("%s:%s:%s", ORDER_CACHE_PREFIX, type, orderId);}
}

6.2 缓存异常处理

@Aspect
@Component
@Slf4j
public class CacheErrorHandler {@Around("@annotation(org.springframework.cache.annotation.Cacheable)")public Object handleCacheError(ProceedingJoinPoint pjp) {try {return pjp.proceed();} catch (Throwable e) {log.error("Cache operation failed", e);// 降级处理:直接访问数据库try {return pjp.proceed();} catch (Throwable ex) {log.error("Database operation also failed", ex);throw new RuntimeException("Service unavailable", ex);}}}
}

6.3 缓存预热

@Component
public class CacheWarmer implements ApplicationRunner {@Autowiredprivate UserService userService;@Overridepublic void run(ApplicationArguments args) {log.info("开始预热缓存...");// 预热重要的用户数据List<Long> importantUserIds = userService.getImportantUserIds();importantUserIds.forEach(userId -> {try {userService.getUserById(userId);log.debug("预热用户缓存: {}", userId);} catch (Exception e) {log.error("预热用户缓存失败: {}", userId, e);}});log.info("缓存预热完成");}
}

7. 性能优化建议

  1. 合理设置缓存大小和过期时间
@Configuration
public class CacheConfig {@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory factory) {// 根据实际业务需求设置缓存配置Map<String, RedisCacheConfiguration> configMap = new HashMap<>();// 高频访问数据 - 短期缓存configMap.put("highFrequency", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).prefixCacheNameWith("hf:").serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)));// 低频访问数据 - 长期缓存configMap.put("lowFrequency", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(24)).prefixCacheNameWith("lf:").serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)));return RedisCacheManager.builder(factory).withInitialCacheConfigurations(configMap).build();}
}
  1. 使用批量操作提高性能
@Service
public class BatchOperationExample {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 批量获取用户信息*/public List<User> batchGetUsers(List<Long> userIds) {List<String> keys = userIds.stream().map(id -> "user:" + id).collect(Collectors.toList());// 批量获取缓存List<Object> cachedUsers = redisTemplate.opsForValue().multiGet(keys);// 处理缓存未命中的情况List<Long> missedIds = new ArrayList<>();List<User> result = new ArrayList<>();for (int i = 0; i < userIds.size(); i++) {if (cachedUsers.get(i) != null) {result.add((User) cachedUsers.get(i));} else {missedIds.add(userIds.get(i));}}if (!missedIds.isEmpty()) {// 批量查询数据库List<User> dbUsers = userMapper.batchSelect(missedIds);// 批量写入缓存Map<String, User> userMap = new HashMap<>();dbUsers.forEach(user -> userMap.put("user:" + user.getId(), user));redisTemplate.opsForValue().multiSet(userMap);result.addAll(dbUsers);}return result;}
}
  1. 使用管道提高性能
@Service
public class PipelineExample {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 使用管道批量操作*/public void batchOperationWithPipeline(List<User> users) {redisTemplate.executePipelined((RedisCallback<Object>) connection -> {for (User user : users) {byte[] key = redisTemplate.getKeySerializer().serialize("user:" + user.getId());byte[] value = redisTemplate.getValueSerializer().serialize(user);connection.set(key, value);connection.expire(key, 1800); // 30分钟过期}return null;});}
}

8. 缓存安全

8.1 防止缓存穿透

@Service
public class CachePenetrationProtection {/*** 使用布隆过滤器防止缓存穿透*/@Cacheable(value = "userCache",key = "#id",unless = "#result == null")public User getUserWithBloomFilter(Long id) {// 先检查布隆过滤器if (!bloomFilter.mightContain(id)) {return null;}// 查询缓存User user = (User) redisTemplate.opsForValue().get("user:" + id);if (user != null) {return user;}// 查询数据库user = userMapper.selectById(id);if (user != null) {redisTemplate.opsForValue().set("user:" + id, user, 30, TimeUnit.MINUTES);} else {// 防止缓存穿透,缓存空值redisTemplate.opsForValue().set("user:" + id, NULL_VALUE, 5, TimeUnit.MINUTES);}return user;}
}

8.2 防止缓存击穿

@Service
public class CacheBreakdownProtection {/*** 使用互斥锁防止缓存击穿*/public User getUserWithMutex(Long id) {String cacheKey = "user:" + id;String lockKey = "lock:" + cacheKey;// 查询缓存User user = (User) redisTemplate.opsForValue().get(cacheKey);if (user != null) {return user;}// 获取互斥锁boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);if (!locked) {// 获取锁失败,等待后重试try {Thread.sleep(100);return getUserWithMutex(id);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException("获取用户信息失败", e);}}try {// 双重检查user = (User) redisTemplate.opsForValue().get(cacheKey);if (user != null) {return user;}// 查询数据库user = userMapper.selectById(id);if (user != null) {redisTemplate.opsForValue().set(cacheKey, user, 30, TimeUnit.MINUTES);}return user;} finally {// 释放锁redisTemplate.delete(lockKey);}}
}

8.3 防止缓存雪崩

@Service
public class CacheAvalancheProtection {/*** 使用随机过期时间防止缓存雪崩*/@Cacheable(value = "userCache",key = "#id",unless = "#result == null")public User getUserWithRandomExpiry(Long id) {User user = userMapper.selectById(id);if (user != null) {// 基础过期时间30分钟,增加随机值(0-5分钟)long randomExpiry = 30 + new Random().nextInt(5);redisTemplate.opsForValue().set("user:" + id, user, randomExpiry, TimeUnit.MINUTES);}return user;}
}

9. 缓存测试

9.1 单元测试

@SpringBootTest
public class CacheTest {@Autowiredprivate UserService userService;@Autowiredprivate CacheManager cacheManager;@Testpublic void testUserCache() {// 第一次调用,应该查询数据库User user1 = userService.getUserById(1L);assertNotNull(user1);// 第二次调用,应该从缓存获取User user2 = userService.getUserById(1L);assertNotNull(user2);assertEquals(user1, user2);// 验证缓存中的数据Cache cache = cacheManager.getCache("userCache");assertNotNull(cache);assertNotNull(cache.get("user:1"));}
}

9.2 性能测试

@SpringBootTest
public class CachePerformanceTest {@Autowiredprivate UserService userService;@Testpublic void testCachePerformance() {int iterations = 1000;long startTime = System.currentTimeMillis();// 预热缓存User user = userService.getUserById(1L);assertNotNull(user);// 测试缓存读取性能for (int i = 0; i < iterations; i++) {user = userService.getUserById(1L);assertNotNull(user);}long endTime = System.currentTimeMillis();long duration = endTime - startTime;log.info("平均响应时间: {}ms", duration / (double) iterations);}
}

这个详细的教程涵盖了 Spring Boot Redis 缓存的各个方面,从基础配置到高级特性,以及性能优化和安全考虑。你可以根据具体项目需求选择合适的部分进行使用和调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92426.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92426.shtml
英文地址,请注明出处:http://en.pswp.cn/web/92426.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

八股——WebSocket

文章目录1、 什么是 WebSocket&#xff1f;与 Http 协议的区别是什么&#xff1f;2、 Http 是如何升级为 WebSocket 的&#xff1f;3、 为什么 WebSocket 可以进行全双工模式的消息传输&#xff0c;而 Http 不可以&#xff1f;4、 什么是 TCP 的沾包和拆包&#xff1f;5、 WebS…

Mysql 如何使用 binlog 日志回滚操作失误的数据

文章目录一、背景二、准备测试数据1. 创建测试表2. 创建测试数据三、模拟误操作四、数据回滚&#xff08;一&#xff09;方案一&#xff1a;云数据库恢复&#xff08;二&#xff09;方案二&#xff1a;手动恢复1. 查询 binlog 日志2. 找到删除语句&#xff0c;手动还原为插入语…

wodpress结构化数据对SEO的作用

在 WordPress 网站中&#xff0c;结构化数据对 SEO 的作用主要体现在以下几个方面&#xff1a; 1. 提升搜索结果的可见性 结构化数据能够帮助搜索引擎更好地理解网页内容&#xff0c;从而以更精准的方式展示搜索结果。通过添加结构化数据&#xff0c;网页可以在搜索结果中显示…

讲一讲@ImportResource

题目详细答案ImportResource是 Spring 框架中的一个注解&#xff0c;用于将传统的 XML 配置文件导入到基于 Java 配置的 Spring 应用程序中。它允许开发者在使用 Java 配置的同时&#xff0c;继续利用现有的 XML 配置文件。这样可以逐步迁移旧的 XML 配置&#xff0c;或者在某些…

解决 Nginx 反代中 proxy_ssl_name 环境变量失效问题:网页能打开但登录失败

前言&#xff1a;在现代企业架构中&#xff0c;多域名反向代理是实现业务隔离、品牌独立的常见方案。然而&#xff0c;看似简单的Nginx配置背后&#xff0c;隐藏着与TLS协议、后端认证逻辑深度绑定的细节陷阱。本文将从原理到实践&#xff0c;详解为何在多域名场景下&#xff0…

三步完成,A100本地vLLM部署gpt-oss,并启动远程可访问api

A100本地vLLM部署gpt-oss&#xff0c;并启动远程可访问api GPT-oss试用 gpt-oss有两个原生配置是目前&#xff08;2025-8-8&#xff09;Ampere系列显卡不支持的&#xff0c;分别是默认的MXFP4量化&#xff0c;以及Flash-attn V3。官方给出的vllm教程也是默认使用的是H系列显卡…

【华为机试】63. 不同路径 II

文章目录63. 不同路径 II题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;解题思路核心思想&#xff1a;动态规划&#xff08;避开障碍&#xff09;算法流程复杂度分析边界与细节方法对比代码实现Go 实现&#xff08;含二维DP / 一维DP / 记忆化&#xff09;测试…

C++ 模拟实现 map 和 set:掌握核心数据结构

C 模拟实现 map 和 set&#xff1a;掌握核心数据结构 文章目录C 模拟实现 map 和 set&#xff1a;掌握核心数据结构一、set 和 map 的结构1.1 set的结构1.2 map的结构二、对红黑树的改造2.1 改造红黑树的节点2.2 改造红黑树2.2.1 仿函数的使用2.2.2 插入函数的改造2.2.3 删除函…

根据ASTM D4169-23e1标准,如何选择合适的流通周期进行测试?

根据ASTM D4169-23e1标准及行业实践&#xff0c;选择流通周期&#xff08;DC&#xff09;需综合以下因素&#xff1a;一、核心选择依据‌产品属性与包装形式‌‌重量体积‌&#xff1a;轻小包裹&#xff08;<4.53kg且<0.056m&#xff09;适用DC2/3/4/6/9/13-17等周期&…

MySQL的触发器:

目录 触发器的概念&#xff1a; 创建触发器&#xff1a; 查看触发器&#xff1a; 查看当前数据库的所有触发器的定义&#xff1a; 查看当前数据中某个触发器的定义&#xff1a; 从系统information_schema的TRIGGERS表中查询"salary_check_trigger"触发器的信息…

基于ubuntu搭建gitlab

原文地址&#xff1a;基于ubuntu搭建gitlab – 无敌牛 欢迎参观我的网站&#xff1a;无敌牛 – 技术/著作/典籍/分享等 之前介绍了一个使用 git openssh-server 搭建一个极简 git 库的方法&#xff0c;感兴趣可以查看往期文章&#xff1a;手搓一个极简远端git库 – 无敌牛 。…

测试GO前沿实验室:为水系电池研究提供多维度表征解决方案

测试GO前沿实验室&#xff1a;为水系电池研究提供多维度表征解决方案随着全球能源转型加速&#xff0c;水系电池因其高安全性、低成本和环境友好特性&#xff0c;成为下一代储能技术的重要发展方向。测试狗前沿实验室针对水系电池研发中的关键科学问题&#xff0c;整合先进表征…

Spring Boot 中 YAML 配置文件详解

Spring Boot 中 YAML 配置文件详解 在 Spring Boot 项目中&#xff0c;配置文件是不可或缺的一部分&#xff0c;用于自定义应用行为、覆盖默认设置。除了传统的 properties 文件&#xff0c;Spring Boot 对 YAML&#xff08;YAML Ain’t Markup Language&#xff09;格式提供了…

Milvus安装可视化工具,attu,保姆级

安装包链接&#xff1a;GitHub - zilliztech/attu: Web UI for Milvus Vector Databasehttps://github.com/zilliztech/attu?tabreadme-ov-file 下滑 举例&#xff1a;windows&#xff1a;下载安装&#xff0c;然后就可以连接了&#xff08;安装完打开后如果需要输入用户名密码…

避免“卡脖子”!如何减少内存I/O延迟对程序的影响?

单来说&#xff0c;内存 IO 就像是计算机的 “数据高速公路”&#xff0c;负责在内存和其他设备&#xff08;如硬盘、CPU 等&#xff09;之间传输数据。它的速度和效率直接影响着计算机系统的整体性能。 你有没有想过&#xff0c;当你点击电脑上的一个应用程序&#xff0c;它是…

V4L2摄像头采集 + WiFi实时传输实战全流程

&#x1f4d6; 推荐阅读&#xff1a;《Yocto项目实战教程:高效定制嵌入式Linux系统》 &#x1f3a5; 更多学习视频请关注 B 站&#xff1a;嵌入式Jerry V4L2摄像头采集 WiFi实时传输实战全流程 1. 实战场景概述 目标&#xff1a; 嵌入式设备&#xff08;如RK3588/正点原子开发…

Java 之 设计模式

1.单例模式1. ​​饿汉式&#xff08;Eager Initialization&#xff09;​​​​核心原理​​&#xff1a;类加载时立即创建实例&#xff0c;通过静态变量直接初始化。​​代码示例​​&#xff1a;public class Singleton {private static final Singleton INSTANCE new Sing…

[激光原理与应用-185]:光学器件 - BBO、LBO、CLBO晶体的全面比较

一、相同点非线性光学晶体属性BBO、LBO、CLBO均为非中心对称晶体&#xff0c;具备非线性光学效应&#xff0c;广泛应用于激光频率转换&#xff08;如倍频、三倍频、和频、差频&#xff09;、光学参量振荡&#xff08;OPO&#xff09;及电光调制等领域。宽透光范围三者均覆盖紫外…

Android APN加载耗时优化可行性分析

背景 根据Android系统底层机制和行业实践,本文讨论 APN 加载耗时从4.2s降至0.8s的数据合理性和技术可行性,需结合具体优化手段和硬件环境综合分析。 以下是关键判断依据及行业参考: ⚙️ 一、APN加载耗时基准参考 未优化场景的典型耗时 首次开机或重置后:APN需从apns-con…

mysql进阶-sql调优

概述优化索引在MySQL初阶的课程中已经介绍了索引&#xff0c;我们知道InnoDB存储引擎使⽤B树作为索引默认的数据结构来组织数据&#xff0c;为频繁查询的列建⽴索引可以有效的提升查询效率&#xff0c;那么如何利⽤索引编写出⾼效的SQL查询语句&#xff1f;以及如何分析某个查询…