Redis - 多集群数据源配置

目录

  • 前言
  • 依赖
  • yml配置
  • redis多集群数据源配置类
    • 思考
  • redis工具类

前言

工作时有一个项目配置了多个redis数据源,使用时出现了指定了使用副数据源,数据却依然使用了主数据源的情况。经过排查,发现配置流程较为繁琐易错,此处做一个记录。

依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-redis</artifactId><version>1.4.1.RELEASE</version>
</dependency>

yml配置

此处设置两个不同的redis地址,可以debug时,在redisTemplate对象中查看此时使用的到底是哪一个数据源,方便排查问题。

spring:redis:jedis:pool:maxActive: 1000minIdle: 1maxWait: 5000maxIdle: 5timeout: 6000msredis-one: # 第一个redis(主)集群配置cluster:node: localhost:6379password: 123456redis-two: # 第二个redis(其他)集群配置cluster:node: 127.0.0.1:6379password: 123456

redis多集群数据源配置类

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
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.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;@Configuration
@EnableCaching
@Slf4j
public class RedisDataSourceConfig extends CachingConfigurerSupport {@Resourceprivate Environment environment;@Resourceprivate RedisProperties redisProperties;/*** 主业务redis操作模板** @param factoryOne* @return*/@Bean(name = "redisOneTemplate")@Primarypublic RedisTemplate<String, Object> redisOneTemplate(@Autowired @Qualifier("factoryOne") JedisConnectionFactory factoryOne) {return getRedisTemplate(factoryOne);}/*** 副redis操作模板* 注意:初始化配置有误,导致实际查询的还是第一个redis(redis-one)配置* @param factoryTwo* @return*/@Bean(name = "redisTwoTemplate")public RedisTemplate<String, Object> redisTwoTemplate(@Autowired @Qualifier("factoryTwo") JedisConnectionFactory factoryTwo) {return getRedisTemplate(factoryTwo);}/*** 副redis操作模板(真)* 真实指向 redis-two配置* @param factoryTwoReal* @return*/@Bean(name = "redisTwoRealTemplate")public RedisTemplate<String, Object> redisTwoRealTemplate(@Autowired @Qualifier("factoryTwoReal") JedisConnectionFactory factoryTwoReal) {return getRedisTemplate(factoryTwoReal);}/*============================  集群模式配置 start  ===========================*//*** 指向redis-one配置*/@Bean("factoryOne")@Primarypublic JedisConnectionFactory factoryOne(RedisStandaloneConfiguration redisConfigOne, JedisClientConfiguration clientConfig) {return new JedisConnectionFactory(redisConfigOne, clientConfig);}/*** 真实指向redis-one配置*/@Bean("factoryTwo")public JedisConnectionFactory factoryTwo(RedisStandaloneConfiguration redisConfigTwo, JedisClientConfiguration clientConfig) {return new JedisConnectionFactory(redisConfigTwo, clientConfig);}/*** 真实指向redis-two配置*/@Bean("factoryTwoReal")public JedisConnectionFactory factoryTwoReal(@Autowired @Qualifier("redisConfigTwo") RedisStandaloneConfiguration redisConfigTwo, JedisClientConfiguration clientConfig) {return new JedisConnectionFactory(redisConfigTwo, clientConfig);}// 读取第一个redis配置@Primary	@Bean("redisConfigOne")public RedisStandaloneConfiguration redisConfigOne() {String nodeStrAry = environment.getProperty("spring.redis.redis-one.cluster.nodes");String password = environment.getProperty("spring.redis.redis-one.password");assert nodeStrAry != null;assert password != null;RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();String[] hostPortAry = nodeStrAry.split(":");redisStandaloneConfiguration.setHostName(hostPortAry[0]);redisStandaloneConfiguration.setPort(Integer.parseInt(hostPortAry[1]));redisStandaloneConfiguration.setPassword(password);return redisStandaloneConfiguration;}// 读取第二个redis配置@Bean("redisConfigTwo")public RedisStandaloneConfiguration redisConfigTwo() {String nodeStrAry = environment.getProperty("spring.redis.redis-two.cluster.nodes");String password = environment.getProperty("spring.redis.redis-two.password");assert nodeStrAry != null;assert password != null;RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();String[] hostPortAry = nodeStrAry.split(":");redisStandaloneConfiguration.setHostName(hostPortAry[0]);redisStandaloneConfiguration.setPort(Integer.parseInt(hostPortAry[1]));redisStandaloneConfiguration.setPassword(password);return redisStandaloneConfiguration;}/*================================集群模式 end===============================*/@Bean("clientConfig")public JedisClientConfiguration jedisClientConfiguration() {JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMaxIdle());poolConfig.setMinIdle(redisProperties.getJedis().getPool().getMinIdle());poolConfig.setMaxTotal(redisProperties.getJedis().getPool().getMaxActive());poolConfig.setMaxWaitMillis(redisProperties.getJedis().getPool().getMaxWait().toMillis());return JedisClientConfiguration.builder().connectTimeout(redisProperties.getTimeout()).usePooling().poolConfig(poolConfig).build();}private RedisClusterConfiguration getRedisClusterConfiguration(String nodeStrAry, String password) {RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();String[] serverArray = nodeStrAry.split(",");Set<RedisNode> nodes = new HashSet<>();for (String ipPort : serverArray) {String[] ipAndPort = ipPort.split(":");nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1])));}redisClusterConfiguration.setClusterNodes(nodes);redisClusterConfiguration.setPassword(password);return redisClusterConfiguration;}private RedisTemplate<String, Object> getRedisTemplate(JedisConnectionFactory factory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());redisTemplate.setConnectionFactory(factory);return redisTemplate;}/*** json序列化** @return*/@Beanpublic RedisSerializer<Object> jackson2JsonRedisSerializer() {Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);ObjectMapper mapper = new ObjectMapper();mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);serializer.setObjectMapper(mapper);return serializer;}}

注解:
@Primary :优先考虑注入的类
@Qualifier :通过控制里面的字符串来匹配类上的字符串达到控制注入的效果。

思考

factoryTwo方法与factoryTwoReal方法看起来都调用了redis-two的配置方法,为什么factoryTwo实际调用的还是redis-one的配置呢?

答:区别就在于入参@Autowired @Qualifier(“redisConfigTwo”) RedisStandaloneConfiguration redisConfigTwo,factoryTwo方法未使用@Qualifier(“redisConfigTwo”)指定redis-two的配置方法,实际上注入的是标记了@Primary的redis-one配置方法。

redis工具类

为主数据源与副数据源分别创建工具类或直接使用注解指定当前使用的数据源

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;/***  Redis主数据源工具类*/
@Component
public class RedisOneUtils {// 指向redis-one@Resource(name = "redisOneTemplate")private RedisTemplate<String, Object> redisTemplate;/*** 指定缓存失效时间** @param key  键* @param time 时间(秒)* @return*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据key 获取过期时间** @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在** @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存** @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete(CollectionUtils.arrayToList(key));}}}//============================String=============================/*** 普通缓存获取** @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入** @param key   键* @param value 值* @return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间** @param key   键* @param value 值* @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 递增** @param key   键* @param delta 要增加几(大于0)* @return*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForValue().increment(key, delta);}/*** 递减** @param key   键* @param delta 要减少几(小于0)* @return*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForValue().increment(key, -delta);}//================================Map=================================/*** HashGet** @param key  键 不能为null* @param item 项 不能为null* @return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** 获取hashKey对应的所有键值** @param key 键* @return 对应的多个键值*/public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);}/*** HashSet** @param key 键* @param map 对应多个键值* @return true 成功 false 失败*/public boolean hmset(String key, Map<String, Object> map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** HashSet 并设置时间** @param key  键* @param map  对应多个键值* @param time 时间(秒)* @return true成功 false失败*/public boolean hmset(String key, Map<String, Object> map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** @param key   键* @param item  项* @param value 值* @return true 成功 false失败*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** @param key   键* @param item  项* @param value 值* @param time  时间(秒)  注意:如果已存在的hash表有时间,这里将会替换原有的时间* @return true 成功 false失败*/public boolean hset(String key, String item, Object value, long time) {try {redisTemplate.opsForHash().put(key, item, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值** @param key  键 不能为null* @param item 项 可以使多个 不能为null*/public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);}/*** 判断hash表中是否有该项的值** @param key  键 不能为null* @param item 项 不能为null* @return true 存在 false不存在*/public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);}/*** hash递增 如果不存在,就会创建一个 并把新增后的值返回** @param key  键* @param item 项* @param by   要增加几(大于0)* @return*/public double hincr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, by);}/*** hash递减** @param key  键* @param item 项* @param by   要减少记(小于0)* @return*/public double hdecr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, -by);}//============================set=============================/*** 根据key获取Set中的所有值** @param key 键* @return*/public Set<Object> sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 根据value从一个set中查询,是否存在** @param key   键* @param value 值* @return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {e.printStackTrace();return false;}}/*** 将数据放入set缓存** @param key    键* @param values 值 可以是多个* @return 成功个数*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 将set数据放入缓存** @param key    键* @param time   时间(秒)* @param values 值 可以是多个* @return 成功个数*/public long sSetAndTime(String key, long time, Object... values) {try {Long count = redisTemplate.opsForSet().add(key, values);if (time > 0) {expire(key, time);}return count;} catch (Exception e) {e.printStackTrace();return 0;}}/*** 获取set缓存的长度** @param key 键* @return*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的** @param key    键* @param values 值 可以是多个* @return 移除的个数*/public long setRemove(String key, Object... values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}//===============================list=================================/*** 获取list缓存的内容** @param key   键* @param start 开始* @param end   结束  0 到 -1代表所有值* @return*/public List<Object> lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 获取list缓存的长度** @param key 键* @return*/public long lGetListSize(String key) {try {return redisTemplate.opsForList().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 通过索引 获取list中的值** @param key   键* @param index 索引  index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推* @return*/public Object lGetIndex(String key, long index) {try {return redisTemplate.opsForList().index(key, index);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将list放入缓存** @param key   键* @param value 值* @return*/public boolean lSet(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, Object value, long time) {try {redisTemplate.opsForList().rightPush(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key   键* @param value 值* @return*/public boolean lSet(String key, List<Object> value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, List<Object> value, long time) {try {redisTemplate.opsForList().rightPushAll(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据索引修改list中的某条数据** @param key   键* @param index 索引* @param value 值* @return*/public boolean lUpdateIndex(String key, long index, Object value) {try {redisTemplate.opsForList().set(key, index, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 移除N个值为value** @param key   键* @param count 移除多少个* @param value 值* @return 移除的个数*/public long lRemove(String key, long count, Object value) {try {Long remove = redisTemplate.opsForList().remove(key, count, value);return remove;} catch (Exception e) {e.printStackTrace();return 0;}}/*** 模糊查询获取key值** @param pattern* @return*/public Set keys(String pattern) {return redisTemplate.keys(pattern);}/*** 使用Redis的消息队列** @param channel* @param message 消息内容*/public void convertAndSend(String channel, Object message) {redisTemplate.convertAndSend(channel, message);}/*** 根据起始结束序号遍历Redis中的list** @param listKey* @param start   起始序号* @param end     结束序号* @return*/public List<Object> rangeList(String listKey, long start, long end) {//绑定操作BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);//查询数据return boundValueOperations.range(start, end);}/*** 弹出右边的值 --- 并且移除这个值** @param listKey*/public Object rifhtPop(String listKey) {//绑定操作BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);return boundValueOperations.rightPop();}/*** 有序集合添加** @param key* @param value* @param scoure*/public boolean zAdd(String key, Object value, double scoure) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();return zset.add(key, value, scoure);}/*** 移除集合中时间过期的** @param key* @return*/public boolean removeSet(String key, long max) {try {long count = redisTemplate.opsForZSet().removeRangeByScore(key, 0, max);System.out.println("count===>" + count);if (count > 0) {return true;}} catch (Exception e) {return false;}return false;}/*** 移除集合中某个成员** @param key* @param value* @return*/public Boolean delSetNum(String key, String value) {try {long cnt = redisTemplate.opsForZSet().remove(key, value);if (cnt > 0) {return true;}} catch (Exception e) {return false;}return false;}public <T> boolean setString(String key, T value) {try {//任意类型转换成StringString val = beanToString(value);if (val == null || val.length() <= 0) {return false;}redisTemplate.opsForValue().set(key, val);return true;} catch (Exception e) {return false;}}public <T> boolean setStringTime(String key, T value, long timeout) {try {//任意类型转换成StringString val = beanToString(value);if (val == null || val.length() <= 0) {return false;}redisTemplate.opsForValue().set(key, val, timeout, TimeUnit.MILLISECONDS);return true;} catch (Exception e) {return false;}}public <T> T get(String key, Class<T> clazz) {try {Object object = redisTemplate.opsForValue().get(key);if (object == null) {return null;}String value = String.valueOf(object);return stringToBean(value, clazz);} catch (Exception e) {return null;}}public <T> boolean delete(String key) {try {if (key == null || key.length() <= 0) {return false;}redisTemplate.delete(key);return true;} catch (Exception e) {return false;}}public boolean exists(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {return false;}}@SuppressWarnings("unchecked")private <T> T stringToBean(String value, Class<T> clazz) {if (value == null || value.length() <= 0 || clazz == null) {return null;}if (clazz == int.class || clazz == Integer.class) {return (T) Integer.valueOf(value);} else if (clazz == long.class || clazz == Long.class) {return (T) Long.valueOf(value);} else if (clazz == String.class) {return (T) value;} else {return JSON.toJavaObject(JSON.parseObject(value), clazz);}}/*** @param value 任意类型* @return String*/private <T> String beanToString(T value) {if (value == null) {return null;}Class<?> clazz = value.getClass();if (clazz == int.class || clazz == Integer.class) {return "" + value;} else if (clazz == long.class || clazz == Long.class) {return "" + value;} else if (clazz == String.class) {return (String) value;} else {return JSON.toJSONString(value);}}//=========BoundListOperations 用法 End============}

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

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

相关文章

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入) 反转(转移)控制(IOC Inverse of Control) 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成好处&#xff1a;…

七、并发工具(上)

一、自定义线程池 1&#xff09;背景&#xff1a; 在 QPS 量比较高的情况下&#xff0c;我们不可能说所有的访问都创建一个线程执行&#xff0c;这会导致内存占用过高&#xff0c;甚至有可能出现 out of memory另外也要考虑 cpu 核数&#xff0c;如果请求超过了cpu核数&#…

【bitonicSort学习】

bitonicSort学习 什么是Bitonic Sort核心 什么是Bitonic Sort https://zhuanlan.zhihu.com/p/53963918 这个是用来并行排序的一个操作 之前学过一些CPU排序&#xff0c;快排 冒泡 归并啥的&#xff0c;有一些能转成并行&#xff0c;有一些不适合 像快排这种二分策略就可以考虑…

2024美赛数学建模D题思路源码

比赛当天第一时间更新&#xff01; 赛题目的 赛题目的&#xff1a; 问题描述&#xff1a; 解题的关键&#xff1a; 问题一. 问题分析 问题解答 问题二. 问题分析 问题解答 问题三. 问题分析 问题解答 问题四. 问题分析 问题解答 问题五. 问题分析 问题解答

Vue3的自定义指令怎么迁移到nuxt3

一、找到Vue3中指令的源码 const DISTANCE 100; // 距离 const ANIMATIONTIME 500; // 500毫秒 let distance: number | null null,animationtime: number | null null; const map new WeakMap(); const ob new IntersectionObserver((entries) > {for (const entrie…

草图导入3d后模型贴材质的步骤?---模大狮模型网

3D模型在导入草图大师后出现混乱可能有多种原因&#xff0c;以下是一些可能的原因和解决方法&#xff1a; 模型尺寸问题&#xff1a;如果3D模型的尺寸在导入草图大师时与画布尺寸不匹配&#xff0c;可能导致模型混乱。解决方法是在3D建模软件中调整模型的尺寸&#xff0c;使其适…

深入理解 Java 变量类型、声明及应用

Java 变量 变量是用于存储数据值的容器。在 Java 中&#xff0c;有不同类型的变量&#xff0c;例如&#xff1a; String - 存储文本&#xff0c;例如 "你好"。字符串值用双引号引起来。int - 存储整数&#xff08;全数字&#xff09;&#xff0c;没有小数&#xff…

华为手表开发:WATCH 和GT系列,2.生成密钥和证书请求文件,生成签名和配置签名

华为手表开发:WATCH 3 Pro(2)生成密钥和证书请求文件,生成签名和配置签名 初环境与设备生成密钥生成签名初 希望能写一些简单的教程和案例分享给需要的人 鸿蒙可穿戴开发 环境与设备 系统:window 设备:HUAWEI WATCH 3 Pro 开发工具:DevEco Studio 3.1.0.100 外包开发…

FreeRTOS使用计数信号量进行任务同步与资源管理

FreeRTOS使用计数信号量进行任务同步与资源管理 介绍 在多任务系统中&#xff0c;任务之间的同步和对共享资源的管理是非常重要的。FreeRTOS 提供了丰富的同步机制&#xff0c;其中计数信号量是一种强大的工具&#xff0c;用于实现任务之间的同步和对资源的访问控制。 什么是…

figure方法详解之清除图形内容

figure方法详解之清除图形内容 一 clf():二 clear():三 clear()方法和clf()方法的区别&#xff1a; 前言 Hello 大家好&#xff01;我是甜美的江。 在数据可视化中&#xff0c;Matplotlib 是一个功能强大且广泛使用的库&#xff0c;它提供了各种方法来创建高质量的图形。在 Mat…

SpringBoot 多模块开发 笔记(一)

多模块开发 简易版 dao 层 也可以说是 Mapper 层web 层 将 controller 放在这一层 还有 统一返回类型 和 自定义异常 也在放在这里 启动类也放在这里model 层 也就是 数据对象 比如常见的 User 类server 层 业务逻辑层 或者说 service 层更好 创建步骤 创建一个正常的 Sprin…

unity 拖入文件 窗口大小

目录 unity 拖入文件插件 设置窗口大小 unity 拖入文件插件 GitHub - Bunny83/UnityWindowsFileDrag-Drop: Adds file drag and drop support for Unity standalong builds on windows. 设置窗口大小 file build

Iceberg从入门到精通系列之二十一:Spark集成Iceberg

Iceberg从入门到精通系列之二十一&#xff1a;Spark集成Iceberg 一、在 Spark 3 中使用 Iceberg二、添加目录三、创建表四、写五、读六、Catalogs七、目录配置八、使用目录九、替换会话目录十、使用目录特定的 Hadoop 配置值十一、加载自定义目录十二、SQL 扩展十三、运行时配置…

python--整体的模块

1、python程序的架构&#xff1a;是将一个程序分割为源代码文件的集合以及将这些部分连接在一起的方法2、在python中&#xff0c;一个py文件就是一个模块&#xff0c;多个模块组成一个包。3、python的模块的执行环境&#xff1a;一个模块包含了变量、函数、类以及其他的模块&am…

电子电器架构——车载网关转发buffer心得汇总

电子电器架构——车载网关转发buffer心得汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力…

Debezium系列之:字段schema详解

Debezium系列之:字段schema详解 一、字段schema二、字段schema参数解释一、字段schema {"type":"bytes","optional":true,"name":"org.apache.kafka.connect.data.Decimal","version":1,"parameters"…

手写Spring框架之: HelloSpring

代码路径&#xff1a;GitHub - tanglijiong/MiniSpringFramework: 用于spring学习和演示 1. 项目结构包介绍 core&#xff1a;核心功能&#xff0c;如Bean的创建和管理beans&#xff1a;与Bean定义和处理相关的类context&#xff1a;应用上下文相关&#xff0c;管理不同的Bean…

vue2父组件向子组件传值时,子组件同时接收多个数据类型,控制台报警的问题

最近项目遇到一个问题,就是我的父组件向子组件(公共组件)传值时,子组件同时接收多个数据类型,控制台报警的问题,如下图,子组件明明写了可同时接收字符串,整型和布尔值,但控制台依旧报警: 仔细检查父组件,发现父组件是这样写的: <common-tabletooltip :content=…

2024 springboot Mybatis-flex 打包出错

Mybatis-flex官网&#xff1a;快速开始 - MyBatis-Flex 官方网站 从 Mybatis-flex官网获取模板后&#xff0c;加入自己的项目内容想打包确保错&#xff0c;先试试一下方法 这里改成skip的默认是true改成false&#xff0c;再次打包就可以了

Git系列---标签管理

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.理解标签2.创建标签…