架构设计之自定义延迟双删缓存注解(下)

架构设计之自定义延迟双删缓存注解(下)

小薛博客官方架构设计之自定义延迟双删缓存注解(下)地址

为了保证@Cache@ClearAndReloadCache的灵活性,特意加入EL表达式解析

1、Cache

package com.xx.cache;import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;/*** @Author: xueqimiao* @Date: 2025/3/17 14:24*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cache {/*** 过期时间,默认60s* @return*/long expire() default 60 ;TimeUnit unit() default TimeUnit.SECONDS;/*** 缓存标识name* @return*/String name() default "";/*** SpringEL表达式,解析占位符对应的匹配value值* @return*/String matchValue();}

2、CacheAspect

package com.xx.cache;import com.xx.common.Result;
import com.xx.utils.RedisService;
import com.xx.utils.ValidationUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;/*** @Author: xueqimiao* @Date: 2025/3/17 14:25*/
@Component
@Aspect
@Slf4j
public class CacheAspect {@Resourceprivate RedisService redisService;/*** aop切点* 拦截被指定注解修饰的方法*/@Pointcut("@annotation(com.xx.cache.Cache)")public void cache() {}/*** 缓存操作** @param pjp* @return*/@Around("cache()")public Object toCache(ProceedingJoinPoint joinPoint) {Object result = null;try {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(),signature.getMethod().getParameterTypes());Cache annotation = method.getAnnotation(Cache.class);String matchedValue = annotation.matchValue();String keyPrefix = annotation.name();long time = annotation.expire();TimeUnit unit = annotation.unit();// 解析EL表达式SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(matchedValue);EvaluationContext context = new StandardEvaluationContext();// 获取参数Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++) {context.setVariable(parameterNames[i], args[i]);}String key = keyPrefix + "::" + expression.getValue(context).toString();result = redisService.get(key);if (!ValidationUtil.isEmpty(result)) {return Result.ok(result);}// 执行目标方法result = joinPoint.proceed();Object res = result;if (result instanceof Result) {res = ((Result<?>) result).getResult();}redisService.set(key, res, time, unit);} catch (Throwable e) {throw new RuntimeException(e);}return result;}}

3、ClearAndReloadCache

package com.xx.cache;import java.lang.annotation.*;/*** @Author: xueqimiao* @Date: 2025/3/17 14:26*/
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
public @interface ClearAndReloadCache {/*** 缓存标识name* @return*/String name() default "";/*** SpringEL表达式,解析占位符对应的匹配value值* @return*/String matchValue();
}

4、ClearAndReloadCacheAspect

package com.xx.cache;import com.xx.utils.RedisUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** @Author: xueqimiao* @Date: 2025/3/17 14:26*/
@Aspect
@Component
@Slf4j
public class ClearAndReloadCacheAspect {@Resourceprivate RedisUtils redisUtils;/*** 切入点* 切入点,基于注解实现的切入点  加上该注解的都是Aop切面的切入点*/@Pointcut("@annotation(com.xx.cache.ClearAndReloadCache)")public void pointCut() {}/*** 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型** @param proceedingJoinPoint*/@Around("pointCut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) {log.info("----------- 环绕通知 -----------");log.info("环绕通知的目标方法名:" + joinPoint.getSignature().getName());try {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(),signature.getMethod().getParameterTypes());ClearAndReloadCache annotation = method.getAnnotation(ClearAndReloadCache.class);//反射得到自定义注解的方法对象String matchedValue = annotation.matchValue();String keyPrefix = annotation.name(); //获取自定义注解的方法对象的参数即name// 解析EL表达式SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(matchedValue);EvaluationContext context = new StandardEvaluationContext();// 获取参数Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++) {context.setVariable(parameterNames[i], args[i]);}String key = keyPrefix + "::" + expression.getValue(context).toString();redisUtils.del(key);//模糊删除redis的key值//执行加入双删注解的改动数据库的业务 即controller中的方法业务Object proceed = null;try {proceed = joinPoint.proceed();//放行} catch (Throwable throwable) {throwable.printStackTrace();}//新开开一个线程延迟0.5秒(时间可以改成自己的业务需求),等着mysql那边业务操作完成//在线程中延迟删除  同时将业务代码的结果返回 这样不影响业务代码的执行new Thread(() -> {try {Thread.sleep(500);redisUtils.del(key);log.info("-----------0.5秒后,在线程中延迟删除完毕 -----------");} catch (InterruptedException e) {e.printStackTrace();}}).start();return proceed;//返回业务代码的值} catch (Throwable e) {throw new RuntimeException(e);}}
}

5、UserController

package com.xx.controller;import com.xx.cache.Cache;
import com.xx.cache.ClearAndReloadCache;
import com.xx.common.Result;
import com.xx.entity.User;
import com.xx.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;/*** @Author: xueqimiao* @Date: 2025/3/17 14:27*/
@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@PostMapping("/updateData")@ClearAndReloadCache(name = "user", matchValue = "#user.id")public Result updateData(@RequestBody User user) {return userService.update(user);}@GetMapping("/get")@Cache(name = "user", matchValue = "#id")public Result get(@RequestParam Integer id) {return userService.get(id);}}

6、RedisService

package com.xx.utils;import jakarta.annotation.Resource;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;/*** @Author: xueqimiao* @Date: 2023/7/17 13:46*/
@Component
public class RedisService {@Resourcepublic RedisTemplate redisTemplate;/*** 默认过期时长,单位:秒 一天*/public final static long DEFAULT_EXPIRE = 60 * 60 * 24;/*** 不设置过期时长*/public final static long NOT_EXPIRE = -1;private static double size = Math.pow(2, 32);/*=======================================String - Object=======================================*//*** 缓存基本的对象,Integer、String、实体类等** @param key* @param value* @return*/public boolean set(final String key, Object value) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.set(key, value);result = true;} catch (Exception e) {e.printStackTrace();}return result;}/*** 写入缓存设置时效时间** @param key* @param value* @return*/public boolean set(final String key, Object value, Long expireTime) {return set(key, value, expireTime, TimeUnit.SECONDS);}public boolean set(final String key, Object value, Long expireTime, TimeUnit unit) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.set(key, value);redisTemplate.expire(key, expireTime, unit);result = true;} catch (Exception e) {e.printStackTrace();}return result;}public <T> void setCacheObject(final String key, final T value) {redisTemplate.opsForValue().set(key, value);}/*** 获得缓存的Object对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public Object getCache(final String key) {return redisTemplate.opsForValue().get(key);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key) {ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T get(final String key) {ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 读取缓存** @param key* @return*/public <T> T get(final String key, Class<T> clazz) {ValueOperations<Serializable, Object> operation = redisTemplate.opsForValue();T result = (T) operation.get(key);return result;}/*** 设置有效时间** @param key     Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout) {return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key     Redis键* @param timeout 超时时间* @param unit    时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit) {return redisTemplate.expire(key, timeout, unit);}/*** 获取有效时间** @param key Redis键* @return 有效时间*/public long getExpire(final String key) {return redisTemplate.getExpire(key);}/*** 判断 key是否存在** @param key 键* @return true 存在 false不存在*/public Boolean hasKey(String key) {return redisTemplate.hasKey(key);}/*** 删除单个对象** @param key*/public void delete(String key) {redisTemplate.delete(key);}/*** 删除集合对象** @param collection*/public void delete(Collection collection) {redisTemplate.delete(collection);}/*** 判断缓存中是否有对应的value** @param key* @return*/public boolean exists(final String key) {return redisTemplate.hasKey(key);}/*** 累加 1** @param key 缓存的键值* @return*/public Long increment(final String key) {return increment(key, 1L);}public Long decrement(final String key) {return decrement(key, 1L);}/*** 累加 指定值** @param key 缓存的键值* @param num 累加的数量* @return*/public Long increment(final String key, Long num) {return redisTemplate.opsForValue().increment(key, num);}public Long decrement(final String key, Long num) {return redisTemplate.opsForValue().decrement(key, num);}/*** 获得缓存的基本对象key列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern) {return redisTemplate.keys(pattern);}/*=======================================List=======================================*//*** 缓存List数据** @param key      缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long listRightPush(final String key, final List<T> dataList) {Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}public long listRightPush(String key, String value) {Long listSize = redisTemplate.opsForList().rightPush(key, value);return null == listSize ? 0 : listSize;}public <T> long listLeftPush(final String key, final List<T> dataList) {Long count = redisTemplate.opsForList().leftPushAll(key, dataList);return count == null ? 0 : count;}public long listLeftPush(String key, String value) {Long listSize = redisTemplate.opsForList().leftPush(key, value);return null == listSize ? 0 : listSize;}public long listRemove(String key, long count, String value) {Long remove = redisTemplate.opsForList().remove(key, count, value);return null == remove ? 0 : remove;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key) {return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存List数据** @param key      缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList) {Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 列表获取** @param k* @param start* @param end* @return*/public <T> List<T> listRange(String k, long start, long end) {ListOperations<String, T> list = redisTemplate.opsForList();return list.range(k, start, end);}public <T> List<T> listRange(String k) {return listRange(k, 0, -1);}/*=======================================Set=======================================*//*** 缓存Set** @param key     缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()) {setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key) {return redisTemplate.opsForSet().members(key);}/*** 集合添加** @param key* @param value*/public void add(String key, Object value) {SetOperations<String, Object> set = redisTemplate.opsForSet();set.add(key, value);}/*** 集合获取** @param key* @return*/public Set<Object> setMembers(String key) {SetOperations<String, Object> set = redisTemplate.opsForSet();return set.members(key);}public <T> T pop(String key) {SetOperations<String, T> set = redisTemplate.opsForSet();return set.pop(key);}public <T> List<T> pop(String key, Long num) {SetOperations<String, T> set = redisTemplate.opsForSet();return set.pop(key, num);}/*=======================================ZSet=======================================*//*** 有序集合添加** @param key* @param value* @param scoure*/public void zAdd(String key, Object value, double scoure) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();zset.add(key, value, scoure);}/*** 有序集合获取** @param key* @param scoure* @param scoure1* @return*/public Set<Object> rangeByScore(String key, double scoure, double scoure1) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();redisTemplate.opsForValue();return zset.rangeByScore(key, scoure, scoure1);}/*** 有序集合获取排名** @param key   集合名称* @param value 值*/public Long zRank(String key, Object value) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();return zset.rank(key, value);}/*** 有序集合获取排名** @param key*/public Set<ZSetOperations.TypedTuple<Object>> zRankWithScore(String key, long start, long end) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();Set<ZSetOperations.TypedTuple<Object>> ret = zset.rangeWithScores(key, start, end);return ret;}/*** 有序集合添加** @param key* @param value*/public Double zSetScore(String key, Object value) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();return zset.score(key, value);}/*** 有序集合添加分数** @param key* @param value* @param scoure*/public void incrementScore(String key, Object value, double scoure) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();zset.incrementScore(key, value, scoure);}/*** 有序集合获取排名** @param key*/public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithScore(String key, long start, long end) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeByScoreWithScores(key, start, end);return ret;}/*** 有序集合获取排名** @param key*/public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithRank(String key, long start, long end) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeWithScores(key, start, end);return ret;}/*=======================================Hash=======================================*//*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key) {return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key   Redis键* @param hKey  Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value) {redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key  Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey) {HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 获取多个Hash中的数据** @param key   Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 哈希 添加** @param key* @param hashKey* @param value*/public void hmSet(String key, Object hashKey, Object value) {HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();hash.put(key, hashKey, value);}/*** 哈希获取数据** @param key* @param hashKey* @return*/public Object hmGet(String key, Object hashKey) {HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();return hash.get(key, hashKey);}/*=======================================Bit=======================================*//*** 写入缓存** @param key* @param offset 位 8Bit=1Byte* @return*/public boolean setBit(String key, long offset, boolean isShow) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.setBit(key, offset, isShow);result = true;} catch (Exception e) {e.printStackTrace();}return result;}/*** 写入缓存** @param key* @param offset* @return*/public boolean getBit(String key, long offset) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();result = operations.getBit(key, offset);} catch (Exception e) {e.printStackTrace();}return result;}public void saveDataToRedis(String name) {Double index = Math.abs(name.hashCode() % size);long indexLong = index.longValue();boolean availableUsers = setBit("availableUsers", indexLong, true);}public boolean getDataToRedis(String name) {Double index = Math.abs(name.hashCode() % size);long indexLong = index.longValue();return getBit("availableUsers", indexLong);}
}

博客心语

在Java编程的征程中,我们都是追梦人。每一次编写代码,都是在编织一个关于未来的故事。这个故事可能是一个高效的电商系统,让购物变得更加便捷;也可能是一个智能的医疗应用,拯救无数的生命。无论你的目标是什么,Java都是你实现梦想的有力武器。所以,不要停下你前进的脚步,不断探索Java的深度和广度,让你的代码充满生命力,因为你正在用一种伟大的语言塑造着一个充满无限可能的未来。

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

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

相关文章

rosbag|ROS中.bag数据包转换为matlab中.mat数据类型

代码见代码 msg_dict中设置自定义消息类型 test_config中设置需要记录的具体的值 test_config中topic_name以及message_type照搬plotjuggler打开时的参数 最后生成.mat文件在matlab中进行使用

基于动态 FOF(基金中的基金)策略的基金交易推荐系统的设计与实现思路

下面为你呈现一个基于动态 FOF&#xff08;基金中的基金&#xff09;策略的基金交易推荐系统的设计与实现思路&#xff0c;同时给出一个简单的 Python 示例代码。 系统设计 1. 需求分析 收集各类基金的历史数据&#xff0c;涵盖净值、收益率、风险指标等。依据动态 FOF 策略…

搭建主从DNS、nfs、nginx

任务需求&#xff1a; 客户端通过访问 www.nihao.com 后&#xff0c;能够通过 dns 域名解析&#xff0c;访问到 nginx 服务中由 nfs 共享的首页文件&#xff0c;内容为&#xff1a;Very good, you have successfully set up the system. 各个主机能够实现时间同步&#xff0c;…

JS 对象转数组,数组转对象

数据格式 objMap : {apiP: 8000, sder: true, host: "1.111", wPort: "1335" }要求&#xff1a;将 objMap 转化为 数组 const equipArray Object.keys(objMap ).map(key > {return {name: key,value: objMap [key]}打印结果 数组转为对象 let equipAr…

vue - [Vue warn]: Duplicate keys detected: ‘0‘. This may cause an update error.

问题描述&#xff1a; vue项目中&#xff0c;对表单数组赋值时&#xff0c;控制台抛出警告&#xff1a; 问题代码&#xff1a; 问题分析&#xff1a; 1、Vue 要求每个虚拟 DOM 节点必须有唯一的 key。该警告信息通常出现在使用v-for循环的场景中&#xff0c;多个同级节点使用…

DeepSeek V3–0324 vs DeepSeek-V3, 排名最高非推理模型

最近DeepSeek V3 升级。 本文将带您了解该模型的核心特性、基准表现,以及如何通过Hugging Face推理终端和OpenRouter平台亲身体验。我们还将通过创意生成与逻辑分析两大测试案例,直观展示其卓越性能。 DeepSeek-V3-0324 2025年3月24日,深度求索(DeepSeek)AI正式发布了V3…

docker使用uv安装依赖

官方使用 FastAPI 官方 Dockerfile 中用了两次&#xff1a; RUN --mounttypecache,target/root/.cache/uv \--mounttypebind,sourceuv.lock,targetuv.lock \--mounttypebind,sourcepyproject.toml,targetpyproject.toml \uv sync --frozen --no-install-project # ✅ 第一次…

3.0 Disruptor的使用介绍(一)

Disruptor: 其官网定义为&#xff1a;“A High Performance Inter-Thread Messaging Library”&#xff0c;即&#xff1a;线程间的高性能消息框架&#xff0c;与Labview的生产者、消费者模型很相似。 其组成部分比较多&#xff0c;先介绍几个常用的概念&#xff1a; …

在 Windows 系统下,将 FFmpeg 编译为 .so 文件

1. 准备环境 确保你的 Windows 系统已安装以下工具&#xff1a; Android Studio NDK&#xff08;Native Development Kit&#xff09; MSYS2&#xff08;用于提供类 Unix 环境&#xff09; FFmpeg 源码 Git Bash&#xff08;可选&#xff0c;推荐使用&#xff09; 安装 …

leetcode二叉树3

404.左叶子之和 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 24示例 2: 输入: root [1] 输…

QT网络通信的接口与使用

文章目录 前言1.服务端实现流程1.1步骤 1&#xff1a;创建 QTcpServer 并监听端口1.2步骤 2&#xff1a;处理新连接请求1.3步骤 3&#xff1a;接收客户端数据1.4步骤 4&#xff1a;处理客户端断开 2.客户端实现流程2.1步骤 1&#xff1a;创建 QTcpSocket 并连接服务器2.2步骤 2…

华为OD机试2025A卷七日集训第1期 - 按算法分类,由易到难,循序渐进,玩转OD(Python/JS/C/C++)

目录 一、适合人群二、本期训练时间三、如何参加四、7日集训第1期五、精心挑选21道高频100分经典题目&#xff0c;作为入门。第1天、逻辑分析第2天、逻辑分析第3天、逻辑分析第4天、逻辑分析第5天、双指针第6天、二叉树第7天、回溯 六、集训总结六、国内直接使用最新GPT-4.5、满…

Qt 重入和线程安全

重入和线程安全 在整个文档中&#xff0c;"重入"和 "线程安全 "这两个术语被用来标记类和函数&#xff0c;以表明它们在多线程应用程序中的使用方式&#xff1a; 线程安全函数可以同时被多个线程调用&#xff0c;即使调用使用的是共享数据&#xff0c;因…

Elasticsearch:构建 AI 驱动的搜索体验

Elasticsearch 介绍 当你开始使用 Elastic 时&#xff0c;你将使用 Elasticsearch Relevance Engine™&#xff08;ESRE&#xff09;&#xff0c;它专为 AI 搜索应用程序提供支持。借助 ESRE&#xff0c;你可以利用一整套开发者工具&#xff0c;包括 Elastic 的文本搜索、向量…

鸿蒙生态开发

鸿蒙生态开发概述 鸿蒙生态是华为基于开源鸿蒙&#xff08;OpenHarmony&#xff09;构建的分布式操作系统生态&#xff0c;旨在通过开放共享的模式连接智能终端设备、操作系统和应用服务&#xff0c;覆盖消费电子、工业物联网、智能家居等多个领域。以下从定义与架构、核心技术…

JVM如何处理Java中的精度转换: 从源码到字节码

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

vue-next-admin修改配置指南

官方文档地址&#xff1a;vue-next-admin 1.如何开启侧边栏logo 在scr-layout-navbars-topBar-setings.vue中添加 getThemeConfig.value.isShowLogo true; 设置为true即可默认打开 2.修改侧边栏顶部的logo与文字 先把想要的图标存到我的项目然后下载 然后把后面的几个文件拉…

gin学习

gin学习笔记&#xff0c;不仅包含了基本的增删查改外&#xff0c;还包括参数传递&#xff0c;上传下载&#xff0c;模版、session与中间件等&#xff0c;方便收藏自习可用 文章目录 获得个请求get打印字符串get请求xmlget请求跳转http方法路由可以通过Context的Param方法来获取…

Flutter运行错误:UG! exception in phase ‘semantic analysis‘

最近在Mac Mini M4上通过Android Studio导入Flutter项目并运行&#xff0c;结果一直跑不起来&#xff0c;错误日志如下&#xff1a; 执行命令查看版本信息&#xff1a; flutter doctor --verbose通过输出信息Java version OpenJDK Runtime Environment (build 21.0.41242208…