spring sharding JDBC 动态调整数据库连接
spring sharding JDBC 动态调整数据库连接
通过重写ShardingSphereDataSource类来实现
代码
package org.apache.shardingsphere.driver.jdbc.core.datasource;import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.driver.jdbc.adapter.AbstractDataSourceAdapter;
import org.apache.shardingsphere.driver.jdbc.context.CachedDatabaseMetaData;
import org.apache.shardingsphere.driver.jdbc.context.JDBCContext;
import org.apache.shardingsphere.driver.state.DriverStateContext;
import org.apache.shardingsphere.infra.config.RuleConfiguration;
import org.apache.shardingsphere.infra.config.checker.RuleConfigurationCheckerFactory;
import org.apache.shardingsphere.infra.config.database.DatabaseConfiguration;
import org.apache.shardingsphere.infra.config.database.impl.DataSourceProvidedDatabaseConfiguration;
import org.apache.shardingsphere.infra.config.mode.ModeConfiguration;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
import org.apache.shardingsphere.infra.config.scope.GlobalRuleConfiguration;
import org.apache.shardingsphere.infra.datasource.props.DataSourceProperties;
import org.apache.shardingsphere.infra.datasource.props.DataSourcePropertiesCreator;
import org.apache.shardingsphere.infra.instance.definition.InstanceDefinition;
import org.apache.shardingsphere.infra.instance.definition.InstanceType;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.infra.rule.builder.schema.DatabaseRulesBuilder;
import org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.mode.manager.ContextManagerBuilderFactory;
import org.apache.shardingsphere.mode.manager.ContextManagerBuilderParameter;
import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistService;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.spring.boot.ShardingSphereAutoConfiguration;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** @author qyc* @version 1.0*/
@Slf4j
public final class ShardingSphereDataSource extends AbstractDataSourceAdapter implements AutoCloseable {private final String databaseName;private final ContextManager contextManager;private final JDBCContext jdbcContext;private ContextManagerBuilderParameter contextManagerBuilderParameter;private ModeConfiguration modeConfiguration;private Collection<RuleConfiguration> ruleConfigs;private Properties properties;public ShardingSphereDataSource(final String databaseName, final ModeConfiguration modeConfig) throws SQLException {this.databaseName = databaseName;this.modeConfiguration = modeConfig;this.properties = new Properties();this.ruleConfigs = new LinkedList<>();contextManager = createContextManager(databaseName, modeConfig, new HashMap<>(), this.ruleConfigs, this.properties);jdbcContext = new JDBCContext(contextManager.getDataSourceMap(databaseName));}/*** {@link ShardingSphereAutoConfiguration#shardingSphereDataSource(org.springframework.beans.factory.ObjectProvider, org.springframework.beans.factory.ObjectProvider)}** @param databaseName* @param modeConfig* @param dataSourceMap* @param ruleConfigs* @param props* @throws SQLException*/public ShardingSphereDataSource(final String databaseName, final ModeConfiguration modeConfig, final Map<String, DataSource> dataSourceMap,final Collection<RuleConfiguration> ruleConfigs, final Properties props) throws SQLException {checkRuleConfiguration(databaseName, ruleConfigs);this.modeConfiguration = modeConfig;this.databaseName = databaseName;contextManager = createContextManager(databaseName, modeConfig, dataSourceMap, ruleConfigs, null == props ? new Properties() : props);this.ruleConfigs = ruleConfigs;this.properties = props;jdbcContext = new JDBCContext(contextManager.getDataSourceMap(databaseName));}/*** 更新现有的数据库配置** @param addDataSourcePropertiesMap 添加的配置* @param dropDataSourceNames 移除的配置* @param updateSources 修改的配置* @param newDataNodes 新的节点使用配置* @throws Exception */public void updateContextMetaData(final Map<String, DataSourceProperties> addDataSourcePropertiesMap, final Collection<String> dropDataSourceNames, Map<String, DataSourceProperties> updateSources, String newDataNodes) throws Exception {if (CollectionUtils.isEmpty(addDataSourcePropertiesMap) && CollectionUtils.isEmpty(dropDataSourceNames) && CollectionUtils.isEmpty(updateSources)) {if (!StringUtils.isEmpty(newDataNodes)) {this.rebuildShardingSphereRule(newDataNodes);}return;}Map<String, DataSourceProperties> refreshProperties = new HashMap<>();Map<String, DataSource> oldDataSources = new HashMap<>(this.contextManager.getDataSourceMap(databaseName));Map<String, DataSource> closeDataSources = new HashMap<>();if (!CollectionUtils.isEmpty(addDataSourcePropertiesMap)) {log.info("添加新的db:{}", addDataSourcePropertiesMap.keySet());this.contextManager.addResource(this.databaseName, addDataSourcePropertiesMap);refreshProperties.putAll(addDataSourcePropertiesMap);}if (!CollectionUtils.isEmpty(dropDataSourceNames)) {log.info("移除旧的db:{}", dropDataSourceNames);this.contextManager.dropResource(this.databaseName, dropDataSourceNames);dropDataSourceNames.forEach(s -> {closeDataSources.put(s, oldDataSources.get(s));});}if (!CollectionUtils.isEmpty(updateSources)) {log.info("更新db:{}", updateSources.keySet());this.contextManager.dropResource(this.databaseName, updateSources.keySet());this.contextManager.addResource(this.databaseName, updateSources);refreshProperties.putAll(updateSources);}log.info("重新加载shardingRule");this.rebuildShardingSphereRule(newDataNodes);log.info("重新构建managerBuildParameter");Map<String, DataSource> dataSourceMap = this.contextManager.getDataSourceMap(databaseName);this.contextManagerBuilderParameter = this.builderParameter(this.databaseName, this.modeConfiguration, dataSourceMap, this.ruleConfigs, this.properties);closeDataSources.forEach((k, closeDataSource) -> {try {log.info("关闭原dataSources:{}", k);if (closeDataSource instanceof DruidDataSource) {((DruidDataSource) closeDataSource).close();}} catch (Exception e) {log.warn("db:{}close时出现异常,异常为:{}", k, e.getMessage(), e);}});}private Map<String, DataSourceProperties> getDataSourcePropertiesMap(final Map<String, DataSource> dataSourceMap) {Map<String, DataSourceProperties> result = new LinkedHashMap<>(dataSourceMap.size(), 1);for (Map.Entry<String, DataSource> each : dataSourceMap.entrySet()) {result.put(each.getKey(), DataSourcePropertiesCreator.create(each.getValue()));}return result;}@SuppressWarnings("unchecked")private void checkRuleConfiguration(final String databaseName, final Collection<RuleConfiguration> ruleConfigs) {ruleConfigs.forEach(each -> RuleConfigurationCheckerFactory.findInstance(each).ifPresent(optional -> optional.check(databaseName, each)));}private ContextManager createContextManager(final String databaseName, final ModeConfiguration modeConfig, final Map<String, DataSource> dataSourceMap,final Collection<RuleConfiguration> ruleConfigs, final Properties props) throws SQLException {ContextManagerBuilderParameter parameter = this.builderParameter(databaseName, modeConfig, dataSourceMap, ruleConfigs, props);this.contextManagerBuilderParameter = parameter;return ContextManagerBuilderFactory.getInstance(modeConfig).build(parameter);}private ContextManagerBuilderParameter builderParameter(final String databaseName, final ModeConfiguration modeConfig, final Map<String, DataSource> dataSourceMap,final Collection<RuleConfiguration> ruleConfigs, final Properties props) {ContextManagerBuilderParameter parameter = ContextManagerBuilderParameter.builder().modeConfig(modeConfig).databaseConfigs(Collections.singletonMap(databaseName, new DataSourceProvidedDatabaseConfiguration(dataSourceMap, ruleConfigs))).globalRuleConfigs(ruleConfigs.stream().filter(each -> each instanceof GlobalRuleConfiguration).collect(Collectors.toList())).props(props).instanceDefinition(new InstanceDefinition(InstanceType.JDBC)).build();return parameter;}private Optional<CachedDatabaseMetaData> createCachedDatabaseMetaData(final Map<String, DataSource> dataSources) throws SQLException {if (dataSources.isEmpty()) {return Optional.empty();}try (Connection connection = dataSources.values().iterator().next().getConnection()) {return Optional.of(new CachedDatabaseMetaData(connection.getMetaData()));}}@Overridepublic Connection getConnection() throws SQLException {return DriverStateContext.getConnection(databaseName, contextManager, jdbcContext);}@Overridepublic Connection getConnection(final String username, final String password) throws SQLException {return getConnection();}/*** Close data sources.** @param dataSourceNames data source names to be closed* @throws Exception exception*/public void close(final Collection<String> dataSourceNames) throws Exception {Map<String, DataSource> dataSourceMap = contextManager.getDataSourceMap(databaseName);for (String each : dataSourceNames) {close(dataSourceMap.get(each));}contextManager.close();}private void close(final DataSource dataSource) throws Exception {if (dataSource instanceof AutoCloseable) {((AutoCloseable) dataSource).close();}}@Overridepublic void close() throws Exception {close(contextManager.getDataSourceMap(databaseName).keySet());}@Overridepublic int getLoginTimeout() throws SQLException {Map<String, DataSource> dataSourceMap = contextManager.getDataSourceMap(databaseName);return dataSourceMap.isEmpty() ? 0 : dataSourceMap.values().iterator().next().getLoginTimeout();}@Overridepublic void setLoginTimeout(final int seconds) throws SQLException {for (DataSource each : contextManager.getDataSourceMap(databaseName).values()) {each.setLoginTimeout(seconds);}}public Set<String> getDataBaseNames() {return this.contextManager.getDataSourceMap(databaseName).keySet();}private void rebuildShardingSphereRule(String newDataNodes) {if (StringUtils.isEmpty(newDataNodes)) {return;}log.info("重新加载db映射:{}", newDataNodes);MetaDataPersistService metaDataPersistService = this.contextManager.getMetaDataContexts().getPersistService().get();Map<String, DatabaseConfiguration> databaseConfigurationMap = getDatabaseConfigMap(Stream.of(this.databaseName).collect(Collectors.toList()), metaDataPersistService, this.contextManagerBuilderParameter);databaseConfigurationMap.get(this.databaseName).getRuleConfigurations().forEach(rule -> {if (rule instanceof ShardingRuleConfiguration) {Collection<ShardingTableRuleConfiguration> tables = ((ShardingRuleConfiguration) rule).getTables();List<ShardingTableRuleConfiguration> newShardingTableRuleConfigurations = tables.stream().map(table -> {String newActualDataNodes = newDataNodes + "." + table.getLogicTable();ShardingTableRuleConfiguration shardingTableRuleConfiguration = new ShardingTableRuleConfiguration(table.getLogicTable(), newActualDataNodes);shardingTableRuleConfiguration.setDatabaseShardingStrategy(table.getDatabaseShardingStrategy());shardingTableRuleConfiguration.setTableShardingStrategy(table.getTableShardingStrategy());shardingTableRuleConfiguration.setReplaceTablePrefix(table.getReplaceTablePrefix());shardingTableRuleConfiguration.setKeyGenerateStrategy(table.getKeyGenerateStrategy());return shardingTableRuleConfiguration;}).collect(Collectors.toList());((ShardingRuleConfiguration) rule).setTables(newShardingTableRuleConfigurations);}});ConfigurationProperties props = new ConfigurationProperties(metaDataPersistService.getPropsService().load());Collection<ShardingSphereRule> build = DatabaseRulesBuilder.build(databaseName, databaseConfigurationMap.get(this.databaseName), props);List<ShardingSphereRule> oldRules = (List<ShardingSphereRule>) this.contextManager.getMetaDataContexts().getMetaData().getDatabases().get(databaseName).getRuleMetaData().getRules();oldRules.clear();oldRules.addAll(build);}private Map<String, DatabaseConfiguration> getDatabaseConfigMap(final Collection<String> databaseNames, final MetaDataPersistService metaDataPersistService,final ContextManagerBuilderParameter parameter) {Map<String, DatabaseConfiguration> result = new HashMap<>(databaseNames.size(), 1);databaseNames.forEach(each -> result.put(each, createDatabaseConfiguration(each, metaDataPersistService, parameter)));return result;}private DatabaseConfiguration createDatabaseConfiguration(final String databaseName, final MetaDataPersistService metaDataPersistService,final ContextManagerBuilderParameter parameter) {Map<String, DataSource> dataSources = this.contextManager.getDataSourceMap(databaseName);Collection<RuleConfiguration> databaseRuleConfigs = metaDataPersistService.getDatabaseRulePersistService().load(databaseName);return new DataSourceProvidedDatabaseConfiguration(dataSources, databaseRuleConfigs);}
}
通过调用重写的DataSource的updateContextMetaData方法来重新加载连接配置
* @param addDataSourcePropertiesMap 添加的配置* @param dropDataSourceNames 移除的配置 * @param updateSources 修改的配置* @param newDataNodes 新的节点使用配置
spring:shardingsphere:datasource:names: ${SHARDING_DATA_SOURCE_NAMES:db-0,db-1}db-0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://${mysql.message0.host}/${mysql.message0.database}?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=falseusername: ${mysql.message0.username}password: ${mysql.message0.password}initialSize: 5 # 初始化大小minIdle: 5 # 最小maxActive: 20 # 最大maxWait: 60000 # 获取连接等待超时的时间...db-1:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.jdbc.Driver...
参数说明
| 参数名 | 说明 |
|---|---|
| addDataSourcePropertiesMap | 添加的db连接,key->连接id,例如配置中的db-0,db-1,value->根据普通db连接配置构建成的DataSourceProperties |
| dropDataSourceNames | 移除的db连接,key->连接id,例如配置中的db-0,db-1 |
| updateSources | 修改的db连接,key->连接id,例如配置中的db-0,db-1,value->根据普通db连接配置构建成的DataSourceProperties |
| newDataNodes | 新的节点使用配置,将配置项中使用的的spring.shardingsphere.datasource.names值更换为该值 |
DataSourceProperties构建类
getDataSource(),传入的值为普通的db连接配置,例如
type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://db3Ip/db3DB?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=falseusername: db3Userpassword: db3PwdinitialSize: 5 # 初始化大小minIdle: 5 # 最小maxActive: 20 # 最大maxWait: 60000 # 获取连接等待超时的时间timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒(3600000:为1小时)minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒validationQuery: select current_timestamp() #SELECT 1 FROM DUAL #用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。testWhileIdle: true #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。建议配置为true,不影响性能,并且保证安全性。testOnBorrow: false #申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。缺省值:truetestOnReturn: false #归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。缺省值:falsepoolPreparedStatements: true #打开PSCache,并且指定每个连接上PSCache的大小#是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。5.5及以上版本有PSCache,建议开启。缺省值:falsemaxPoolPreparedStatementPerConnectionSize: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100。
package com.kittlen.provider.config.sharding;import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.apache.shardingsphere.infra.datasource.pool.creator.DataSourcePoolCreator;
import org.apache.shardingsphere.infra.datasource.props.DataSourceProperties;
import org.apache.shardingsphere.infra.datasource.props.DataSourcePropertiesCreator;
import org.apache.shardingsphere.infra.exception.ShardingSphereException;
import org.apache.shardingsphere.infra.expr.InlineExpressionParser;
import org.apache.shardingsphere.spring.boot.datasource.AopProxyUtils;
import org.apache.shardingsphere.spring.boot.util.PropertyUtil;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.stereotype.Component;import javax.naming.NamingException;
import javax.sql.DataSource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** @author kittlen* @version 1.0*/
public class MyShardingDataSource {private static final String PREFIX = "spring.shardingsphere.datasource.";private static final String DATA_SOURCE_NAME = "name";private static final String DATA_SOURCE_NAMES = "names";private static final String DATA_SOURCE_TYPE = "type";private static final String JNDI_NAME = "jndi-name";/*** Get data source map.** @param environment spring boot environment* @return data source map*/public static Map<String, DataSource> getDataSourceMap(final Environment environment) {Map<String, DataSource> result = new LinkedHashMap<>();for (String each : getDataSourceNames(environment)) {try {result.put(each, getDataSource(environment, each));} catch (final NamingException ex) {throw new ShardingSphereException("Can't find JNDI data source.", ex);}}return result;}/*** Get data source map.** @param environment spring boot environment* @return data source map*/public static Map<String, DataSourceProperties> getDataSourcePropertiesMap(final Environment environment) {Map<String, DataSourceProperties> result = new LinkedHashMap<>();for (String each : getDataSourceNames(environment)) {try {result.put(each, getDataSourceProperties(environment, each));} catch (final NamingException ex) {throw new ShardingSphereException("Can't find JNDI data source.", ex);}}return result;}private static List<String> getDataSourceNames(final Environment environment) {StandardEnvironment standardEnv = (StandardEnvironment) environment;standardEnv.setIgnoreUnresolvableNestedPlaceholders(true);String dataSourceNames = standardEnv.getProperty(PREFIX + DATA_SOURCE_NAME);if (Strings.isNullOrEmpty(dataSourceNames)) {dataSourceNames = standardEnv.getProperty(PREFIX + DATA_SOURCE_NAMES);}return new InlineExpressionParser(dataSourceNames).splitAndEvaluate();}private static DataSource getDataSource(final Environment environment, final String dataSourceName) throws NamingException {Map<String, Object> dataSourceProps = PropertyUtil.handle(environment, String.join("", PREFIX, dataSourceName), Map.class);Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource [%s] properties.", dataSourceName);if (dataSourceProps.containsKey(JNDI_NAME)) {return getJNDIDataSource(dataSourceProps.get(JNDI_NAME).toString());}return DataSourcePoolCreator.create(new DataSourceProperties(dataSourceProps.get(DATA_SOURCE_TYPE).toString(), PropertyUtil.getCamelCaseKeys(dataSourceProps)));}private static DataSourceProperties getDataSourceProperties(final Environment environment, final String dataSourceName) throws NamingException {Map<String, Object> dataSourceProps = PropertyUtil.handle(environment, String.join("", PREFIX, dataSourceName), Map.class);Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource [%s] properties.", dataSourceName);if (dataSourceProps.containsKey(JNDI_NAME)) {return DataSourcePropertiesCreator.create(getJNDIDataSource(dataSourceProps.get(JNDI_NAME).toString()));}return new DataSourceProperties(dataSourceProps.get(DATA_SOURCE_TYPE).toString(), PropertyUtil.getCamelCaseKeys(dataSourceProps));}public static DataSourceProperties getDataSourceProperties(Map<String, Object> dataSourceProps) throws NamingException {if (dataSourceProps.containsKey(JNDI_NAME)) {return DataSourcePropertiesCreator.create(getJNDIDataSource(dataSourceProps.get(JNDI_NAME).toString()));}return new DataSourceProperties(dataSourceProps.get(DATA_SOURCE_TYPE).toString(), PropertyUtil.getCamelCaseKeys(dataSourceProps));}public static DataSource getDataSource(Map<String, Object> dataSourceProps) throws NamingException {if (dataSourceProps.containsKey(JNDI_NAME)) {return getJNDIDataSource(dataSourceProps.get(JNDI_NAME).toString());}return DataSourcePoolCreator.create(new DataSourceProperties(dataSourceProps.get(DATA_SOURCE_TYPE).toString(), PropertyUtil.getCamelCaseKeys(dataSourceProps)));}private static DataSource getJNDIDataSource(final String jndiName) throws NamingException {JndiObjectFactoryBean bean = new JndiObjectFactoryBean();bean.setResourceRef(true);bean.setJndiName(jndiName);bean.setProxyInterface(DataSource.class);bean.afterPropertiesSet();return (DataSource) AopProxyUtils.getTarget(bean.getObject());}
}相关文章:
spring sharding JDBC 动态调整数据库连接
spring sharding JDBC 动态调整数据库连接 通过重写ShardingSphereDataSource类来实现 代码 package org.apache.shardingsphere.driver.jdbc.core.datasource;import com.alibaba.druid.pool.DruidDataSource; import lombok.extern.slf4j.Slf4j; import org.apache.shardi…...
解决CondaHTTPError HTTP 000 CONNECTION FAILED for url解决方法
解决CondaHTTPError: HTTP 000 CONNECTION FAILED for url解决方法 问题:使用conda install命令安装包提示CondaHTTPError: HTTP 000 CONNECTION FAILED for url 分析:网络连接问题,大概率是网速不行或者源没有换 解决方案:修改国…...
10 创建型模式-原型模式
引言: 创建对象的五种方式: 通过new关键字通过Class类的newInstance()方法通过Constructor类的newInstance()方法利用Clone方法反序列化 Clone方法: 其实现方式正是通过调用 Object 类的 clone() 方法来完成。 protected native Object cl…...
MSQL系列(七) Mysql实战-SQL语句Join,exists,in的区别
Mysql实战-SQL语句Join,exists,in的区别 前面我们讲解了索引的存储结构,BTree的索引结构,以及索引最左侧匹配原则及讲解一下常用的SQL语句的优化建议,今天我们来详细讲解一下 我们经常使用的 join, exist&…...
最新壁纸自动采集系统网站PHP源码/360壁纸官方数据接口采集/ZHEYI采集源码
源码介绍: 最新壁纸自动采集系统网站PHP源码,它是ZHEYI自动采集源码,能够在360壁纸官方数据接口采集。很好用的壁纸网站源码分享,仅供学习,请勿商用。 ZHEYI自动采集壁纸PHP源码,能全自动采集高清壁纸网源…...
Redis在分布式场景下的应用
分布式缓存 缓存的基本作用是在高并发场景下对应服务的保护缓冲 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: redis由于高强度性能采用内存 但是意味着丢失的风险单结点redis并发能力有限分布式服务中数据过多 依赖内存的redis 明显单机不…...
2316. 统计无向图中无法互相到达点对数
2316. 统计无向图中无法互相到达点对数 难度: 中等 来源: 每日一题 2023.10.21 给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] [ai, bi] 表示节点 ai 和 bi 之间…...
Selenium定向爬取海量精美图片及搜索引擎杂谈
我自认为这是自己写过博客中一篇比较优秀的文章,同时也是在深夜凌晨2点满怀着激情和愉悦之心完成的。首先通过这篇文章,你能学到以下几点: 1.可以了解Python简单爬取图片的一些思路和方法 2.学习Selenium自动、测试分析动态网页和正则表达式的区别和共同点 …...
面试题—JAVA基础①
文章目录 1.Java面向对象有哪些特征?2.ArrayList和LinkedList有什么区别?3.Java接口和抽象类有哪些区别?4.hashcode和equals如何使用?5.try-catch6.局部变量和实例变量7.String、StringBuffer、StringBuilder 的区别?8…...
naive-ui的n-data-table标签奇特bug记录
具体参考之前的博文:vueday02——使用naive-ui做一个ACM看榜-CSDN博客 具体代码在这里面 原因:在本地运行的时候,datatable里面使用列表渲染成字符串前端设置样式进行转换,但是在正式部署的时候,这个组件没有将其自动…...
微信小程序OA会议系统个人中心授权登入
在我们的完成微信登入授权之前,首先我们要完成我们前面所写的代码,如果有不会的大家可以去看以下我发的前面几个文章链接我发下面了,各位加油! 微信小程序OA会议系统数据交互-CSDN博客 微信小程序会议OA系统其他页面-CSDN博客 …...
Git(一)Windows下安装及使用Git Bash
目录 一、简介1.1 什么是Git?1.2 Git 的主要特点1.3 什么是 Git Bash? 二、下载三、安装3.1 同意协议3.2 选择安装位置3.3 其他配置(【Next】 即可)3.4 安装完毕3.5 打开 Git Bash 官网地址: https://www.git-scm.com/…...
[AUTOSAR][诊断管理][ECU][$19] 读取ECU的DTC故障信息
一、简介 在车载诊断中常用的诊断协议有ISO 14229等,在协议中主要定义了诊断请求、诊断响应的报文格式及ECU该如何处理诊断请求的应用。其中ISO 14229系列标准协议定义了用于行业内诊断通信的需求规范,也就是UDS。UDS主要应用于OSI七层模型的第七层——…...
前端精度问题 (id 返回的和传给后端的不一致问题)
eg: 后端返回 id 10976458979374929 前端获取到的: 10976458979374928 原因: js 中 Number类型范围-2^53 1 到 2^53 - 1 Number.isSafeInteger()用来判断一个整数是否落在这个范围之内。 java中 Long 类型的取值范围是-2^63 1 到 2^63 - 1, 比JavaScript中大很多࿰…...
WPF Material Design UI框架
前言 Material Design in xaml 是开源免费的ui框架,工控软件主打的就是简单界面。 以下简称MD 相关资源 MaterialDesignInXamlToolkit Github 地址 MD 快速启动 MD 案例压缩包 MD 框架使用 启动环境配置 安装Nuget包 App.xaml 配置 <Application x:Class&qu…...
C语言求 3*3 矩阵对角线之和
完整代码: // 求 3*3 矩阵对角线之和 #include<stdio.h>int main() {int n3;int arr[3][3];// 输入矩阵printf("请输入矩阵的元素:\n");for (int i 0; i < n; i){for (int j 0; j < n; j){scanf("%d", &arr[i][j]);}}int su…...
缓存分片中的哈希算法与一致性哈希算法
什么是缓存分片 在高并发场景下,缓存往往成为了瓶颈。这时候,我们可以通过缓存数据分片的方式来解决问题。所谓缓存数据分片,就是将缓存数据按照一定的规则分成多个片段,每个片段由不同的缓存节点负责。这样做有两个好处…...
线框图软件:Balsamiq Wireframes mac中文介绍
Balsamiq Wireframes mac是一款用于创建线框图的软件工具。它旨在帮助用户快速制作出清晰、简洁的界面原型,以便在设计和开发过程中进行协作和沟通。 Balsamiq Wireframes具有简单直观的用户界面,使用户能够快速添加和编辑各种用户界面元素,如…...
【wxWidgets实现透明wxPanel_核心实现_原创思想】
描述 wxWidgets 根本就没有实现过透明wxPanel容器,你设置wxTRANSPARENT_WINDOW,结果sorry 黑色,哈哈哈哈, 就是和你作对.想想当下那么漂亮的桌面, 背景, 透明, 特效.哎 悲哀啊,实现不了,就那死板的界面特性. 网上找了好久,也是乱七八糟,改底层代码还是算了吧,升级特要命.都是只…...
重大技术问题,iPhone 15 Pro Max面临“烧屏门”风波 | 百能云芯
近期,社交媒体平台上陆续涌现大量用户和数码博主就iPhone 15 Pro Max出现烧屏问题的投诉与评论。 烧屏问题是OLED屏幕常见的一个缺陷,这是由OLED屏幕发光机制引发的,OLED屏幕可视为由无数微小的灯泡-像素点构成,这些像素点可以独立…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
