实战 Springboot2 集成Redis 哨兵模式、集群模式、缓存管理、Lettuce拓扑刷新
redis搭建集群模式、Cluster模式(6节点,3主3从集群模式,添加删除节点)_redis cluster节点带数据增减-CSDN博客
Linux部署Redis哨兵集群 一主两从三哨兵(这里使用Redis6,其它版本类似)_linux redis集群模式部署-CSDN博客
配置yaml
redis:redis-configs:redis-order:type: sentinel #standalone clusterhostAndPort: 192.168.132.1:16379,192.168.132.1:16380,192.168.132.1:16381masterName: mymasterpassword: dyj1username:database: 15timeout: 10000pool:max-idle: 8min-idle: 0max-active: 8max-wait: 10000
# redis-pay:
# type: standalone
# hostAndPort: localhost:6380
# database: 14
# timeout: 10000
# pool:
# max-idle: 8 # 连接池中的最大空闲连接 默认 8
# min-idle: 0 # 连接池中的最小空闲连接 默认 0
# max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 默认 8
# max-wait: 10000 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
# redis-order-cluster:
# type: cluster
# hostAndPort: xxx:6379,xxx:6379,xxx:6379
# database: 15
# timeout: 10000
# max-redirects: 3
# pool:
# max-idle: 8
# min-idle: 0
# max-active: 8
# max-wait: 10000
# redis-pay-cluster:
# type: cluster
# hostAndPort: xxx:6379,xxx:6379,xxx:6379
# database: 14
# timeout: 10000
# pool:
# max-idle: 8
# min-idle: 0
# max-active: 8
# max-wait: 10000
cache:caffeine:cache10M: "initialCapacity=20,maximumSize=100,expireAfterWrite=10m,recordStats"cache30s: "initialCapacity=20,maximumSize=100,expireAfterWrite=30s"redis:cache10M: "10"cache30s: "30"
redis连接池
package org.example.redis.config;import freemarker.template.utility.StringUtil;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnection;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.util.Pair;import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.*;@Configuration
@Data
@EnableConfigurationProperties({RedisPoolConfig.class})
public class RedisConnectionFactoryConfig {public static Map<String, LettuceConnectionFactory> redisConnectionFactors = new HashMap<>();@Autowiredprivate RedisPoolConfig redisPoolConfig;@PostConstructpublic void init() {redisPoolConfig.getRedisConfigs().forEach((name, config) -> {LettuceConnectionFactory redisConnectionFactory = null;LettuceClientConfiguration clientConfig = getClientConfiguration(config);switch (config.getType()) {case "standalone":RedisStandaloneConfiguration redisStandaloneConfiguration = createRedisStandaloneConfiguration(config);if (redisStandaloneConfiguration != null) {redisConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);}break;case "cluster":RedisClusterConfiguration redisClusterConfiguration = createRedisClusterConfiguration(config);if (redisClusterConfiguration != null) {redisConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, clientConfig);}break;case "sentinel":RedisSentinelConfiguration redisSentinelConfiguration = createRedisSentinelConfiguration(config);if (redisSentinelConfiguration != null) {redisConnectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration, clientConfig);}break;default:System.out.printf("Unknown type: %d\n", config.getType());break;}if (null != redisConnectionFactory) {// 在获取连接时,先验证连接是否已经中断,如果已经中断则创建一个新的连接redisConnectionFactory.setValidateConnection(true);redisConnectionFactory.afterPropertiesSet(); // start() for spring-data-redis-3.X; afterPropertiesSet() for spring-data-redis-2.XredisConnectionFactors.putIfAbsent(name, redisConnectionFactory);}});}private LettuceClientConfiguration getClientConfiguration(RedisPoolConfig.Config config) {GenericObjectPoolConfig<LettuceConnection> poolConfig = new GenericObjectPoolConfig<>();if (StringUtils.isNotBlank(config.getPool().getMaxActive())) {poolConfig.setMaxTotal(Integer.parseInt(config.getPool().getMaxActive()));}if (StringUtils.isNotBlank(config.getPool().getMaxWait())) {poolConfig.setMaxWait(Duration.ofMillis(Integer.parseInt(config.getPool().getMaxWait())));}if (StringUtils.isNotBlank(config.getPool().getMaxIdle())) {poolConfig.setMaxIdle(Integer.parseInt(config.getPool().getMaxIdle()));}if (StringUtils.isNotBlank(config.getPool().getMinIdle())) {poolConfig.setMinIdle(Integer.parseInt(config.getPool().getMinIdle()));}int timeout = -1;if (StringUtils.isNotBlank(config.getTimeout())) {timeout = Integer.parseInt(config.getTimeout());}if (StringUtils.equals(config.getType(), "cluster")){// 支持自适应集群拓扑刷新和动态刷新源ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder().enableAllAdaptiveRefreshTriggers()// 开启自适应刷新.enableAdaptiveRefreshTrigger()// 开启定时刷新 default 60 SECONDS.enablePeriodicRefresh(Duration.ofSeconds(5)).build();ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder().topologyRefreshOptions(clusterTopologyRefreshOptions)// RedisTemplate通过StatefulRedisClusterConnection发送GET命令到Redis集群。// 根据Redis集群的哈希槽机制,命令被路由到正确的节点。// 如果键不存在于当前节点,会触发重定向(最多max-redirects次)直到找到正确的节点或者达到最大重定向次数。//.maxRedirects().build();LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig)//.readFrom(ReadFrom.SLAVE_PREFERRED) //读写分离:主写从读模式配置.clientOptions(clusterClientOptions).build();return lettuceClientConfiguration;}LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder().shutdownTimeout(Duration.ofMillis(timeout)).poolConfig(poolConfig).build();return clientConfig;}private RedisSentinelConfiguration createRedisSentinelConfiguration(RedisPoolConfig.Config config) {RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();redisSentinelConfiguration.setMaster(config.getMasterName());List<Pair<String, Integer>> hostAndPorts = parseClusterHostAndPort(config.getHostAndPort());if (hostAndPorts.isEmpty()) {return null;}for (Pair<String, Integer> hostAndPort : hostAndPorts) {RedisNode.RedisNodeBuilder builder = RedisNode.newRedisNode()
// .promotedAs(RedisNode.NodeType.SLAVE).listeningAt(hostAndPort.getFirst(), hostAndPort.getSecond());redisSentinelConfiguration.addSentinel(builder.build());}setUsername(config, redisSentinelConfiguration);setPassword(config, redisSentinelConfiguration);setDatabase(config, redisSentinelConfiguration);return redisSentinelConfiguration;}private RedisClusterConfiguration createRedisClusterConfiguration(RedisPoolConfig.Config config) {List<Pair<String, Integer>> hostAndPorts = parseClusterHostAndPort(config.getHostAndPort());if (hostAndPorts.isEmpty()) {return null;}RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();for (Pair<String, Integer> hostAndPort : hostAndPorts) {RedisNode node = new RedisNode(hostAndPort.getFirst(), hostAndPort.getSecond());redisClusterConfiguration.addClusterNode(node);}setUsername(config, redisClusterConfiguration);setPassword(config, redisClusterConfiguration);setClusterConf(config, redisClusterConfiguration);return redisClusterConfiguration;}private RedisStandaloneConfiguration createRedisStandaloneConfiguration(RedisPoolConfig.Config config) {Pair<String, Integer> hostAndPort = parseHostAndPort(config.getHostAndPort());if (null == hostAndPort) {return null;}RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(hostAndPort.getFirst());redisStandaloneConfiguration.setPort(hostAndPort.getSecond());setUsername(config, redisStandaloneConfiguration);setPassword(config, redisStandaloneConfiguration);setDatabase(config, redisStandaloneConfiguration);return redisStandaloneConfiguration;}private void setUsername(RedisPoolConfig.Config config, RedisConfiguration.WithPassword connectionFactory) {if (null != config.getUsername() && !config.getUsername().isEmpty()) {connectionFactory.setUsername(config.getUsername());}}private void setPassword(RedisPoolConfig.Config config, RedisConfiguration.WithPassword connectionFactory) {if (null != config.getPassword() && !config.getPassword().isEmpty()) {connectionFactory.setPassword(config.getPassword());}}private void setDatabase(RedisPoolConfig.Config config, RedisConfiguration.WithDatabaseIndex connectionFactory) {if (null != config.getDatabase() && !config.getDatabase().isEmpty()) {int database = Integer.parseInt(config.getDatabase());connectionFactory.setDatabase(database);}}private void setClusterConf(RedisPoolConfig.Config config, RedisClusterConfiguration redisClusterConfiguration) {if (null != config.getClusterMaxRedirects() && !config.getClusterMaxRedirects().isEmpty()) {int maxRedirects = Integer.parseInt(config.getClusterMaxRedirects());redisClusterConfiguration.setMaxRedirects(maxRedirects);}}private List<Pair<String, Integer>> parseClusterHostAndPort(String hostAndPortStr) {String[] hosts = hostAndPortStr.split(",");List<Pair<String, Integer>> hostAndPorts = new ArrayList<>();for (String hostAndPort : hosts) {Pair<String, Integer> pair = parseHostAndPort(hostAndPort);if (null != pair) {hostAndPorts.add(pair);}}return hostAndPorts;}private Pair<String, Integer> parseHostAndPort(String hostAndPortStr) {String[] hostAndPort = hostAndPortStr.split(":");if (hostAndPort.length != 2) {System.out.printf("Invalid host and port: %s\n", hostAndPortStr);return null;}String host = hostAndPort[0].trim();String port = hostAndPort[1].trim();return Pair.of(host, Integer.parseInt(port));}
}
缓存管理类
package org.example.redis.config;import com.github.benmanes.caffeine.cache.*;
import lombok.extern.slf4j.Slf4j;
import org.example.redis.listener.CaffeineCacheRemovalListener;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Slf4j
@Configuration
@EnableCaching
@EnableConfigurationProperties({CustomerCacheProperties.class})
public class CacheManagerConfiguration {public interface redisCacheKey {public final static String cache10M = "cache10M";public final static String cache30s = "cache30s";}public interface caffeineCacheKey {public final static String cache10M = "cache10M";public final static String cache30s = "cache30s";}@Resourceprivate CustomerCacheProperties customerCacheProperties;public interface CacheManagerNames {String REDIS_CACHE_MANAGER = "redisCacheManager";String LOCAL_CACHE_MANAGER = "localCacheManager";}@Bean(name = CacheManagerNames.REDIS_CACHE_MANAGER)@Primarypublic RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {Map<String, RedisCacheConfiguration> expires = new HashMap<>();customerCacheProperties.getRedis().forEach((name, time) -> {expires.put(name, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(Integer.parseInt(time))));});// Map<String, RedisCacheConfiguration> expires = ImmutableMap.<String, RedisCacheConfiguration>builder()
// .put(cache15, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(15)))
// .put(cache30, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(30)))
// .build();RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(factory).cacheDefaults(cacheConfiguration()).withInitialCacheConfigurations(expires)//事务感知功能有助于确保在事务提交之后缓存和数据库中的数据保持一致,这对于保证数据完整性和避免脏读非常重要。// 然而,这也可能会增加一些性能开销,因此在不需要强一致性的场景下,可以考虑禁用这个特性以提高性能.transactionAware().build();//以锁写入的方式创建RedisCacheWriter对象
// RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);return redisCacheManager;}@Beanpublic RedisCacheConfiguration cacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));}@Bean(name = CacheManagerNames.LOCAL_CACHE_MANAGER)public CacheManager caffeineCacheManager() {List<CaffeineCache> caffeineCaches = new ArrayList<>();customerCacheProperties.getCaffeine().forEach((name, spec) -> {CaffeineSpec caffeineSpec = CaffeineSpec.parse(spec);Caffeine<Object, Object> caffeine = Caffeine.from(caffeineSpec);caffeine.removalListener(new CaffeineCacheRemovalListener());// caffeineCache.executor(cacheExecutor);// 设置定时任务执行过期清除操作//.scheduler(Scheduler.systemScheduler())//cache对缓存写的通知回调caffeine.writer(new CacheWriter<Object, Object>() {@Overridepublic void write(Object key, Object value) {log.info("CacheManager write key={}", key);}@Overridepublic void delete(Object key, Object value, RemovalCause cause) {log.info("CacheManager delete key={}, cause={}", key, cause);}});// //使用CacheLoader创建一个LoadingCache
// caffeine.build(new CacheLoader<String, String>() {
// //同步加载数据
// @Override
// public String load(String key) throws Exception {
// log.info("CacheManager load key={}", key);
// return "value_" + key;
// }
//
// //异步加载数据
// @Override
// public String reload(String key, String oldValue) throws Exception {
// log.info("CacheManager reload key={}", key);
// return "value_" + key;
// }
// });CaffeineCache caffeineCache = new CaffeineCache(name, caffeine.build());caffeineCaches.add(caffeineCache);});SimpleCacheManager simpleCacheManager = new SimpleCacheManager();simpleCacheManager.setCaches(caffeineCaches);return simpleCacheManager;}// @Override
// @Cacheable(key = "#userId", cacheNames = CacheManagerConfiguration.CacheNames.CACHE_15MINS,
// cacheManager = CacheManagerConfiguration.CacheManagerNames.EHCACHE_CACHE_MANAGER)
// public User findUserAccordingToId(Long userId) {
// return userRepository.findById(userId).orElse(User.builder().build());
// }
//
// @Override
// @Cacheable(key = "#username", cacheNames = CacheManagerConfiguration.CacheNames.CACHE_15MINS,
// cacheManager = CacheManagerConfiguration.CacheManagerNames.REDIS_CACHE_MANAGER)
// public User findUserAccordingToUserName(String username) {
// return userRepository.findUserByUsername(username);
// }// @Cacheable( sync = true)}
创建不同的template
package org.example.redis.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import static org.example.redis.config.RedisConnectionFactoryConfig.redisConnectionFactors;@Configuration
@Data
@DependsOn("redisConnectionFactoryConfig")
public class RestTemplateConfig {@Bean(name = "orderStringRedisTemplate")@Primarypublic StringRedisTemplate orderStringRedisTemplate() {return buildStringRedisTemplate(redisConnectionFactors.get("redis-order"));}//
// public RedisTemplate<String, Object> buildObjRedisTemplate(RedisConnectionFactory factory) {
//
// RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// redisTemplate.setConnectionFactory(factory);
//
// Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();
// redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// redisTemplate.setKeySerializer(new StringRedisSerializer());
//
// redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
// redisTemplate.afterPropertiesSet();
// return redisTemplate;
// }public StringRedisTemplate buildStringRedisTemplate(RedisConnectionFactory factory) {StringRedisTemplate redisTemplate = new StringRedisTemplate(factory);Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);return jackson2JsonRedisSerializer;}}
使用实体类接收,使用Map接收。key需要根据自己的业务区分即可
package org.example.redis.config;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "redis")
public class RedisPoolConfig {public Map<String, Config> redisConfigs;@NoArgsConstructor@AllArgsConstructor@Datapublic static class Config {private String name;private String type;private String hostAndPort;private String username;private String password;private String database;
// private String sentinelMasterHostAndPort; // for Sentineprivate String masterName; // for Sentineprivate String clusterMaxRedirects; // for Clusterprivate String timeout;private PoolConfig pool;@Data@NoArgsConstructor@AllArgsConstructorpublic static class PoolConfig {private String maxIdle;private String minIdle;private String maxActive;private String maxWait;}}
}
缓存redis 以及caffeine
package org.example.redis.config;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "cache")
public class CustomerCacheProperties {public Map<String, String> caffeine;public Map<String, String> redis;
}
<!-- lettuce这个客户端--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId> </dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>2.9.3</version> </dependency>
相关文章:
实战 Springboot2 集成Redis 哨兵模式、集群模式、缓存管理、Lettuce拓扑刷新
redis搭建集群模式、Cluster模式(6节点,3主3从集群模式,添加删除节点)_redis cluster节点带数据增减-CSDN博客 Linux部署Redis哨兵集群 一主两从三哨兵(这里使用Redis6,其它版本类似)_linux red…...
MYSQL--binlog和redo log
前言 MySQL日志 MySQL日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中比较重要的就是二进制日志binlog(归档日志)、事务日志redo log(重做日志)和undo log(回滚日志)。 这篇…...

R语言医疗数据分析笔记
分组因子又是什么意思,分组因子和数组的区别是什么 举个实际的例子 分组因子 分组因子是分类变量,用于将数据分成不同组以便于比较或分析。例如,在一项研究中,研究对象的性别(男性和女性)可以视为一个分组…...
SpringBoot使用Jackson-XML裁剪多余的根节点
相关博客:《SpringBoot集成WebService(wsdl)》 比如我们有以下入参 我们只需要MedicalCardInfo这个根节点,其余都不要。如何处理? <A><B><Sender>Aa</Sender><MsgType>Bb</MsgType><MsgVersion>…...

vue路由学习
1、基本了解 (1) (2) (3)在创建vue项目时,就已经勾选了vue-router 2、 (0)自己手写了一个新的组件文件(部门管理)(DeptView.vue) (1&a…...
Kubernetes基于helm部署Kafka_Kraft集群并取消SASL认证且开启数据持久化
注:本文档部署Kafka时,取消了默认的SASL认证的相关配置,并开启了数据持久化。 一、添加并更新Helm仓库 helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update bitnami二、下载并解压kafka的Chart helm pull bitna…...
kotlin -- Flow和Rxjava 对比
引言 我们先说说,关键词 响应式编程,数据流,观察者模式。 观察者模式 一个button setOnClickListener 就是观察者模式。 button是被观察者,它产生一个事件(点击),观察者OnClickListener接收到,做出相…...

【JVM篇】自动内存管理——HotSpot虚拟机对象探秘
目录 前言 一、对象的创建 二、对象的内存布局 三、对象的访问定位 总结 前言 相关文章:【JVM篇】自动内存管理——运行时数据区-CSDN博客 介绍完Java虚拟机的运行时数据区域之后,我们大致明白了Java虚拟机内存模型的概况,但可能会好奇其…...
代谢组数据分析(十七):基于structToolbox代谢组分析流程讲解
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 介绍 structToolbox 是一个广泛使用的工具箱,专门用于代谢组学和其他组学数据的分析。它提供了一系列的数据预处理、统计分析和机器学习方法,特别强调统计和机器学习的重要性。这个工具箱允许…...

科普课堂走起 | 什么是网络安全和数据安全?
网络安全和数据安全是现代数字世界中非常重要的两个概念。让我们来详细了解一下这两个领域。 1.网络安全(Network Security) 网络安全是指保护网络系统免受未经授权的访问、攻击、破坏或滥用的一系列技术和过程。它旨在确保信息的机密性、完整性和可用…...
C语言中常用的函数
处理字符串常用的函数 size_t strspn(const char *s, const char *accept); 函数参数说明: s是被查找的字符串 accepct是要匹配的字符串函数功能说明: 它返回s字符串起始部分中,完全由accept字符串中的字符组成的子字符串的长度函数返回值…...
如何在SpringBoot中进行单元测试?
在Spring Boot中进行单元测试通常会涉及以下几个步骤: 1. 添加测试依赖 确保在你的pom.xml(Maven)或build.gradle(Gradle)中包含了Spring Boot的测试依赖。Spring Boot的Starter依赖spring-boot-starter-test通常已经…...

分布式事务学习整理
一、整体背景 最近在分布式事务领域这块的了解比较少,对自己来说是一个业务盲点,所以想抽空学习以及整理下关于分布式事务的相关知识。 1、分布式事务的发展 总所周知,我们为什么要考虑分布式事务,从一开始发展来说,…...
Conda配置瘦身术:精通conda config --remove命令
Conda配置瘦身术:精通conda config --remove命令 Conda作为Python和其他科学计算语言的包管理器,其灵活性和强大功能在很大程度上依赖于其配置系统。随着时间的推移,Conda配置可能会变得复杂和冗余。conda config --remove命令提供了一种方法…...

Windows下编译安装PETSc
本文记录在Windows下使用MinGW-w64编译安装PETSc的流程。 0、环境 操作系统Windows 11MSYS2msys2-x86_64-20240507 1、开发环境 首先,下载并安装MSYS2,然后编辑PATH环境变量,添加mingw64相关路径:C:\msys64\mingw64\bin。 然…...

phpstudy搭建sqlilabs本地靶场
请先在网上解决好前置条件的下载和安装:phpstudy、vscode、navicat premium(非必要)、sqlilab的压缩包/文件夹 phpstudy--安装sqlilabs 1.打开phpstudy后,我们会用到MySQL5.7.26和Nginx1.15.11 #mysql5.7.26是因为sqlilabs靶场不支持高版本MySQL 2.在软…...

Linux 实验基础环境准备(外网篇)
1.关闭禁用防火墙和selinux systemctl disable firewalld --now sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config2.保证可以连接外网 ping -c3 www.baidu.com 3.配置yum为阿里仓库并下载epel源 mkdir /etc/yum.repos.d/bak/; mv /etc/yum.repos.d/*.repo /e…...
centos8 安装mysql 制作备份数据库脚本
1、配置阿里云源 cd /etc/yum.repos.d/ vim CentOS-Stream-AppStream.repo [appstream] nameCentOS Stream $releasever - AppStream #mirrorlisthttp://mirrorlist.centos.org/?release$stream&arch$basearch&repoAppStream&infra$infra baseurlhttp://mirrors…...

Parsing error: The keyword ‘interface‘ is reserved配置优化
当我们在创建Vue项目时,Vue默认是配置了eslint代码规范检查的,不过我们在项目中Typescript来编写代码时,却报了标题的错误,对应的代码如下: <script lang="ts"> export default{name: "DlHeader" } </script><script setup lang=&quo…...

C语言指针详解-包过系列(二)目录版
C语言指针详解-包过系列(二)目录版 1、数组名的深入理解1.1、数组名的本质1.2、数组名本质的两个例外1.2.1、sizeof(数组名)1.2.2、&数组名 2、使用指针访问数组3、一维数组传参本质4、二级指针4.1、二级指针介绍4.2、二级指针…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...