ShardingSphere-jdbc 5.5.0 + spring boot 基础配置 - 实战篇
ShardingSphere-jdbc 5.5.0 spring boot 基础配置环境准备版本数据库说明集群配置配置文件Maven依赖spring boot配置shardingsphere-jdbc配置自定义配置1SM4加解密存储数据完整的基础配置其他雪花算法自定义worker.id环境准备版本spring boot 2.7.17shardingsphere-jdbc 5.5.0druid 1.2.23数据库说明本示例数据库为单机多库schema的架构以一主一从作为集群演示转为一主多从数据库集群时可自定义修改配置。集群一主一从逻辑主库ds_basic、ds0000、ds0001ds_basic为数据简单、量少的元数据库逻辑从库ds0000_slave、ds0001_slave配置配置文件Maven依赖dependency groupIdorg.apache.shardingsphere/groupId artifactIdshardingsphere-jdbc/artifactId version5.5.0/version exclusions exclusion groupIdorg.apache.shardingsphere/groupId artifactIdshardingsphere-test-util/artifactId /exclusion /exclusions /dependency dependency groupIdorg.yaml/groupId artifactIdsnakeyaml/artifactId version2.2/version /dependencyspring boot配置application.ymlspring: application: name: demo main: allow-bean-definition-overriding: true datasource: driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver url: jdbc:shardingsphere:classpath:sharding.yamlshardingsphere-jdbc配置自定义配置1SM4加解密存储数据shardingsphere 5.5.0移除了sm4算法两种方式解决1、使用官方shardingpshere plugin找到相关组件依赖引用即可2、自己添加sm4算法代码SPI实现。本文使用方式2注意ShardingSphere-jdbc 5.5.1版本加密算法接口升级了以下sm4的SPI代码不适用后续推出适配版本。增加spi扩展org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm增加以下代码com.demo.core.encrypt.SM4EncryptAlgorithmSM4算法代码package com.demo.core.encrypt;import lombok.EqualsAndHashCode;import lombok.Getter;import lombok.SneakyThrows;import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithmMetaData;import org.apache.shardingsphere.infra.algorithm.core.context.AlgorithmSQLContext;import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.nio.charset.StandardCharsets;import java.security.GeneralSecurityException;import java.security.Security;import java.util.Arrays;import java.util.HashSet;import java.util.Optional;import java.util.Properties;import java.util.Set;/**shardingsphere SM4 encrypt algorithm.author Robin Wang*/EqualsAndHashCodepublic final class SM4EncryptAlgorithm implements EncryptAlgorithm {static {Security.addProvider(new BouncyCastleProvider());}Getterprivate final EncryptAlgorithmMetaData metaData new EncryptAlgorithmMetaData(true, true, false);private static final String SM4_KEY “sm4-key”;private static final String SM4_IV “sm4-iv”;private static final String SM4_MODE “sm4-mode”;private static final String SM4_PADDING “sm4-padding”;private static final int KEY_LENGTH 16;private static final int IV_LENGTH 16;private static final Set MODES new HashSet(Arrays.asList(“ECB”, “CBC”));private static final Set PADDINGS new HashSet(Arrays.asList(“PKCS5Padding”, “PKCS7Padding”));private byte[] sm4Key;private byte[] sm4Iv;private String sm4ModePadding;Overridepublic void init(final Properties props) {String sm4Mode createSm4Mode(props);String sm4Padding createSm4Padding(props);sm4ModePadding “SM4/” sm4Mode “/” sm4Padding;sm4Key createSm4Key(props);sm4Iv createSm4Iv(props, sm4Mode);}private String createSm4Mode(final Properties props) {ShardingSpherePreconditions.checkState(props.containsKey(SM4_MODE), () - new AlgorithmInitializationException(this, “%s can not be null or empty”, SM4_MODE));String result String.valueOf(props.getProperty(SM4_MODE)).toUpperCase();ShardingSpherePreconditions.checkState(MODES.contains(result), () - new AlgorithmInitializationException(this, “Mode must be either CBC or ECB”));return result;}private byte[] createSm4Key(final Properties props) {ShardingSpherePreconditions.checkState(props.containsKey(SM4_KEY), () - new AlgorithmInitializationException(this, “%s can not be null”, SM4_KEY));byte[] result ByteUtils.fromHexString(String.valueOf(props.getProperty(SM4_KEY)));ShardingSpherePreconditions.checkState(KEY_LENGTH result.length,() - new AlgorithmInitializationException(this, “Key length must be KEY_LENGTH bytes long”));return result;}private byte[] createSm4Iv(final Properties props, final String sm4Mode) {if (!“CBC”.equalsIgnoreCase(sm4Mode)) {return null;}ShardingSpherePreconditions.checkState(props.containsKey(SM4_IV), () - new AlgorithmInitializationException(this, “%s can not be null”, SM4_IV));String sm4IvValue String.valueOf(props.getProperty(SM4_IV));byte[] result ByteUtils.fromHexString(sm4IvValue);ShardingSpherePreconditions.checkState(IV_LENGTH result.length, () - new AlgorithmInitializationException(this, “Iv length must be IV_LENGTH bytes long”));return result;}private String createSm4Padding(final Properties props) {ShardingSpherePreconditions.checkState(props.containsKey(SM4_PADDING), () - new AlgorithmInitializationException(this, “%s can not be null”, SM4_PADDING));String result String.valueOf(props.getProperty(SM4_PADDING)).toUpperCase().replace(“PADDING”, “Padding”);ShardingSpherePreconditions.checkState(PADDINGS.contains(result), () - new AlgorithmInitializationException(this, “Padding must be either PKCS5Padding or PKCS7Padding”));return result;}Overridepublic String encrypt(Object plainValue, AlgorithmSQLContext algorithmSQLContext) {return null plainValue ? null : ByteUtils.toHexString(encrypt(String.valueOf(plainValue).getBytes(StandardCharsets.UTF_8)));}private byte[] encrypt(final byte[] plainValue) {return handle(plainValue, Cipher.ENCRYPT_MODE);}Overridepublic Object decrypt(Object cipherValue, AlgorithmSQLContext algorithmSQLContext) {return null cipherValue ? null : new String(decrypt(ByteUtils.fromHexString((String) cipherValue)), StandardCharsets.UTF_8);}private byte[] decrypt(final byte[] cipherValue) {return handle(cipherValue, Cipher.DECRYPT_MODE);}SneakyThrows(GeneralSecurityException.class)private byte[] handle(final byte[] input, final int mode) {Cipher cipher Cipher.getInstance(sm4ModePadding, BouncyCastleProvider.PROVIDER_NAME);SecretKeySpec secretKeySpec new SecretKeySpec(sm4Key, “SM4”);Optionalbyte[] sm4Iv Optional.ofNullable(this.sm4Iv);if (sm4Iv.isPresent()) {cipher.init(mode, secretKeySpec, new IvParameterSpec(sm4Iv.get()));} else {cipher.init(mode, secretKeySpec);}return cipher.doFinal(input);}Overridepublic String getType() {return “SM4”;}}sm4算法yaml配置encryptors:sm4_encryptor:type: SM4props:sm4-key: 86C63180C2806ED1F43A859DE501215Csm4-mode: ECBsm4-padding: PKCS5Padding完整的基础配置sharding.yaml配置包括单机模式服务、数据源加解密、规则配置【数据分片、读写分离、数据加密、单表】待新增补充混合规则等mode: type: Standalone repository: type: JDBC databaseName: demo_db dataSources: ds_basic: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/demo_basic?characterEncodingutf-8allowPublicKeyRetrievaltrueuseSSLfalse username: root password: Ph9ep971fm14nYaZsLl9LYMCqX9uJSozYRNgP2VVSj/hbmokn5OC6kpiAA1I0okA9GiDHEo7qHUvRQYYUNZvQ initialSize: 1 minIdle: 1 maxActive: 64 maxWait: 20000 validationQuery: SELECT 1 FROM DUAL validationQueryTimeout: 30000 minEvictableIdleTimeMillis: 300000 maxEvictableIdleTimeMillis: 600000 timeBetweenEvictionRunsMillis: 300000 testOnBorrow: true testWhileIdle: true filters: config, stat, wall connectProperties: connectTimeout: 5000 socketTimeout: 20000 config.decrypt: true config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALZRYgsnvVKPqZTfMOWmmj6OuupFRSk7Vtqv70cG3y6T3bmDcQU3zOC993ozbHpmqeODtuLzURhIuXDMyTKW8CAwEAAQ ds0000: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/demo_0000?characterEncodingutf-8allowPublicKeyRetrievaltrueuseSSLfalse username: root password: Ph9ep971fm14nYaZsLl9LYMCqX9uJSozYRNgP2VVSj/hbmokn5OC6kpiAA1I0okA9GiDHEo7qHUvRQYYUNZvQ initialSize: 1 minIdle: 1 maxActive: 64 maxWait: 20000 validationQuery: SELECT 1 FROM DUAL validationQueryTimeout: 30000 minEvictableIdleTimeMillis: 300000 maxEvictableIdleTimeMillis: 600000 timeBetweenEvictionRunsMillis: 300000 testOnBorrow: true testWhileIdle: true filters: config, stat, wall connectProperties: connectTimeout: 5000 socketTimeout: 20000 config.decrypt: true config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALZRYgsnvVKPqZTfMOWmmj6OuupFRSk7Vtqv70cG3y6T3bmDcQU3zOC993ozbHpmqeODtuLzURhIuXDMyTKW8CAwEAAQ ds0001: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/demo_0001?characterEncodingutf-8allowPublicKeyRetrievaltrueuseSSLfalse username: root password: Ph9ep971fm14nYaZsLl9LYMCqX9uJSozYRNgP2VVSj/hbmokn5OC6kpiAA1I0okA9GiDHEo7qHUvRQYYUNZvQ initialSize: 1 minIdle: 1 maxActive: 64 maxWait: 20000 validationQuery: SELECT 1 FROM DUAL validationQueryTimeout: 30000 minEvictableIdleTimeMillis: 300000 maxEvictableIdleTimeMillis: 600000 timeBetweenEvictionRunsMillis: 300000 testOnBorrow: true testWhileIdle: true filters: config, stat, wall connectProperties: connectTimeout: 5000 socketTimeout: 20000 config.decrypt: true config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALZRYgsnvVKPqZTfMOWmmj6OuupFRSk7Vtqv70cG3y6T3bmDcQU3zOC993ozbHpmqeODtuLzURhIuXDMyTKW8CAwEAAQ ds0000_slave: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.1.88:3306/demo_0000?characterEncodingutf-8allowPublicKeyRetrievaltrueuseSSLfalse username: root password: Ph9ep971fm14nYaZsLl9LYMCqX9uJSozYRNgP2VVSj/hbmokn5OC6kpiAA1I0okA9GiDHEo7qHUvRQYYUNZvQ initialSize: 1 minIdle: 1 maxActive: 64 maxWait: 20000 validationQuery: SELECT 1 FROM DUAL validationQueryTimeout: 30000 minEvictableIdleTimeMillis: 300000 maxEvictableIdleTimeMillis: 600000 timeBetweenEvictionRunsMillis: 300000 testOnBorrow: true testWhileIdle: true filters: config, stat, wall connectProperties: connectTimeout: 5000 socketTimeout: 20000 config.decrypt: true config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALZRYgsnvVKPqZTfMOWmmj6OuupFRSk7Vtqv70cG3y6T3bmDcQU3zOC993ozbHpmqeODtuLzURhIuXDMyTKW8CAwEAAQ ds0001_slave: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.1.88:3306/demo_0001?characterEncodingutf-8allowPublicKeyRetrievaltrueuseSSLfalse username: root password: Ph9ep971fm14nYaZsLl9LYMCqX9uJSozYRNgP2VVSj/hbmokn5OC6kpiAA1I0okA9GiDHEo7qHUvRQYYUNZvQ initialSize: 1 minIdle: 1 maxActive: 64 maxWait: 20000 validationQuery: SELECT 1 FROM DUAL validationQueryTimeout: 30000 minEvictableIdleTimeMillis: 300000 maxEvictableIdleTimeMillis: 600000 timeBetweenEvictionRunsMillis: 300000 testOnBorrow: true testWhileIdle: true filters: config, stat, wall connectProperties: connectTimeout: 5000 socketTimeout: 20000 config.decrypt: true config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALZRYgsnvVKPqZTfMOWmmj6OuupFRSk7Vtqv70cG3y6T3bmDcQU3zOC993ozbHpmqeODtuLzURhIuXDMyTKW8CAwEAAQ rules: # 数据分片 - !SHARDING tables: t_claim_case_mdtrt: actualDataNodes: ds$-{[0000,0001]}.t_claim_case_mdtrt_000$-{0..9} tableStrategy: standard: shardingColumn: transaction_no shardingAlgorithmName: t_claim_case_mdtrt_inline keyGenerateStrategy: column: id keyGeneratorName: snowflake t_claim_case_info: actualDataNodes: ds$-{[0000,0001]}.t_claim_case_info_000$-{0..9} tableStrategy: standard: shardingColumn: transaction_no shardingAlgorithmName: t_claim_case_info_inline keyGenerateStrategy: column: id keyGeneratorName: snowflake defaultShardingColumn: transaction_no bindingTables: - t_claim_case_mdtrt, t_claim_case_info defaultDatabaseStrategy: standard: shardingColumn: transaction_no shardingAlgorithmName: database_inline defaultTableStrategy: none: shardingAlgorithms: database_inline: type: INLINE props: algorithm-expression: ds$-{transaction_no[-8..-5]} t_claim_case_mdtrt_inline: type: INLINE props: algorithm-expression: t_claim_case_mdtrt_$-{transaction_no[-4..-1]} t_claim_case_info_inline: type: INLINE props: algorithm-expression: t_claim_case_info_$-{transaction_no[-4..-1]} keyGenerators: snowflake: type: SNOWFLAKE #数据加密 - !ENCRYPT tables: t_claim_case_info: columns: appl_mobile: cipher: name: appl_mobile encryptorName: sm4_encryptor opsnId_no: cipher: name: opsnId_no encryptorName: sm4_encryptor rpter_id_no: cipher: name: rpter_id_no encryptorName: sm4_encryptor rpter_mobile: cipher: name: rpter_mobile encryptorName: sm4_encryptor encryptors: sm4_encryptor: type: SM4 props: sm4-key: 86C63180C2806ED1F43A859DE501215C sm4-mode: ECB sm4-padding: PKCS5Padding # 单表 - !SINGLE tables: - ds_basic.* # 读写分离 - !READWRITE_SPLITTING dataSources: ds0000: writeDataSourceName: ds0000 readDataSourceNames: - ds0000_slave transactionalReadQueryStrategy: PRIMARY loadBalancerName: random ds0001: writeDataSourceName: ds0001 readDataSourceNames: - ds0001_slave transactionalReadQueryStrategy: PRIMARY loadBalancerName: random loadBalancers: random: type: RANDOM props: sql-show: true max-connections-size-per-query: 5其他雪花算法自定义worker.id集群模式下不同机器需要配置不同的workerId适合使用ShardingSphere Proxy集群模式需要使用第三方配置中心zookeeper)。但这会变更架构且本项目CICD时只有一个war部署weblogic server集群的方式。因此特沿用ShardingSphere JDBC单机模式并且启动服务时添加处理自定义随机数的workerId以适应集群机器部署。1.改造雪花算法代码package com.demo.core.config; import cn.hutool.core.util.RandomUtil; import lombok.Generated; import lombok.Setter; import lombok.SneakyThrows; import org.apache.shardingsphere.infra.algorithm.core.context.AlgorithmSQLContext; import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmExecuteException; import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException; import org.apache.shardingsphere.infra.algorithm.keygen.core.KeyGenerateAlgorithm; import org.apache.shardingsphere.infra.algorithm.keygen.snowflake.SnowflakeKeyGenerateAlgorithm; import org.apache.shardingsphere.infra.algorithm.keygen.snowflake.TimeService; import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions; import org.apache.shardingsphere.infra.instance.InstanceContext; import org.apache.shardingsphere.infra.instance.InstanceContextAware; import org.apache.shardingsphere.infra.instance.workerid.WorkerIdGenerator; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Collection; import java.util.LinkedList; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static org.apache.shardingsphere.infra.instance.workerid.WorkerIdGenerator.WORKER_ID_KEY; /** * ShardingSphere JDBC 随机workerId雪花算法 * * date 2024/10/06 13:00 **/ public class RandomWorkerIdSnowflakeKeyGenerateAlgorithm implements KeyGenerateAlgorithm, InstanceContextAware { public static final long EPOCH; private static final String MAX_VIBRATION_OFFSET_KEY max-vibration-offset; private static final String MAX_TOLERATE_TIME_DIFFERENCE_MILLIS_KEY max-tolerate-time-difference-milliseconds; private static final long SEQUENCE_BITS 12L; private static final long WORKER_ID_BITS 10L; private static final long SEQUENCE_MASK (1 SEQUENCE_BITS) - 1L; private static final long WORKER_ID_LEFT_SHIFT_BITS SEQUENCE_BITS; private static final long TIMESTAMP_LEFT_SHIFT_BITS WORKER_ID_LEFT_SHIFT_BITS WORKER_ID_BITS; private static final int DEFAULT_VIBRATION_VALUE 1; private static final int MAX_TOLERATE_TIME_DIFFERENCE_MILLIS 10; private static final int DEFAULT_WORKER_ID 0; Setter private static TimeService timeService new TimeService(); private final AtomicReferenceInstanceContext instanceContext new AtomicReference(); private final AtomicInteger sequenceOffset new AtomicInteger(-1); private final AtomicLong sequence new AtomicLong(); private final AtomicLong lastMillis new AtomicLong(); private Properties props; private int maxVibrationOffset; private int maxTolerateTimeDifferenceMillis; private static final String randomWorkerId RandomUtil.randomNumbers(3); static { EPOCH LocalDateTime.of(2016, 11, 1, 0, 0, 0).toInstant(ZoneId.systemDefault().getRules().getOffset(Instant.now())).toEpochMilli(); } Override public void init(final Properties props) { props.setProperty(WorkerIdGenerator.WORKER_ID_KEY, randomWorkerId); this.props props; maxVibrationOffset getMaxVibrationOffset(props); maxTolerateTimeDifferenceMillis getMaxTolerateTimeDifferenceMillis(props); } private int getMaxVibrationOffset(final Properties props) { int result Integer.parseInt(props.getOrDefault(MAX_VIBRATION_OFFSET_KEY, DEFAULT_VIBRATION_VALUE).toString()); ShardingSpherePreconditions.checkState(result 0 result SEQUENCE_MASK, () - new AlgorithmInitializationException(this, Illegal max vibration offset.)); return result; } private int getMaxTolerateTimeDifferenceMillis(final Properties props) { int result Integer.parseInt(props.getOrDefault(MAX_TOLERATE_TIME_DIFFERENCE_MILLIS_KEY, MAX_TOLERATE_TIME_DIFFERENCE_MILLIS).toString()); ShardingSpherePreconditions.checkState(result 0, () - new AlgorithmInitializationException(this, Illegal max tolerate time difference milliseconds.)); return result; } Override public void setInstanceContext(final InstanceContext instanceContext) { this.instanceContext.set(instanceContext); if (null ! instanceContext) { instanceContext.generateWorkerId(props); } } Override public CollectionLong generateKeys(final AlgorithmSQLContext context, final int keyGenerateCount) { CollectionLong result new LinkedList(); for (int index 0; index keyGenerateCount; index) { result.add(generateKey()); } return result; } private synchronized Long generateKey() { long currentMillis timeService.getCurrentMillis(); if (waitTolerateTimeDifferenceIfNeed(currentMillis)) { currentMillis timeService.getCurrentMillis(); } if (lastMillis.get() currentMillis) { sequence.set(sequence.incrementAndGet() SEQUENCE_MASK); if (0L sequence.get()) { currentMillis waitUntilNextTime(currentMillis); } } else { vibrateSequenceOffset(); sequence.set(sequenceOffset.get()); } lastMillis.set(currentMillis); return ((currentMillis - EPOCH) TIMESTAMP_LEFT_SHIFT_BITS) | ((long) getWorkerId() WORKER_ID_LEFT_SHIFT_BITS) | sequence.get(); } SneakyThrows(InterruptedException.class) private boolean waitTolerateTimeDifferenceIfNeed(final long currentMillis) { if (lastMillis.get() currentMillis) { return false; } long timeDifferenceMillis lastMillis.get() - currentMillis; ShardingSpherePreconditions.checkState(timeDifferenceMillis maxTolerateTimeDifferenceMillis, () - new AlgorithmExecuteException(this, Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds., lastMillis.get(), currentMillis)); Thread.sleep(timeDifferenceMillis); return true; } private long waitUntilNextTime(final long lastTime) { long result timeService.getCurrentMillis(); while (result lastTime) { result timeService.getCurrentMillis(); } return result; } private void vibrateSequenceOffset() { if (!sequenceOffset.compareAndSet(maxVibrationOffset, 0)) { sequenceOffset.incrementAndGet(); } } private int getWorkerId() { return null instanceContext.get() ? DEFAULT_WORKER_ID : instanceContext.get().getWorkerId(); } Override public String getType() { return RANDOM_WORKER_ID_SNOWFLAKE; } Override public boolean isDefault() { return true; } }2.添加SPI添加以下代码路径com.demo.core.config.RandomWorkerIdSnowflakeKeyGenerateAlgorithm3.修改雪花算法配置

相关新闻

大模型知识梳理(持续更新)

大模型知识梳理(持续更新)

大模型的底层——TrasnsformerTransformer 架构是一种基于自注意力机制(Self-Attention)的深度学习模型,由 Google 团队在 2017 年的论文《Attention Is All You Need》中首次提出。它改变了自然语言处理(NLP)领域&…

2026/5/17 9:32:58 阅读更多 →
薪酬面议,上不封顶 | 自变量机器人深圳/北京招募6D位姿估计、定位、导航、SLAM算法工程师等岗位

薪酬面议,上不封顶 | 自变量机器人深圳/北京招募6D位姿估计、定位、导航、SLAM算法工程师等岗位

公司介绍自变量机器人成立于2023年12月。公司聚焦自研通用具身智能大模型及人形机器人本体,以软硬一体化的路径,实现通用机器人。自变量自研的「Great Wall」具身智能大模型系列的WALL-A,具备自主感知、推理、长程决策交互,世界模…

2026/7/5 16:18:50 阅读更多 →
SocketTool、串口调试助手、MQTT中间件基础

SocketTool、串口调试助手、MQTT中间件基础

目录 一、SocketTool 二、串口通信 三、MQTT中间件 一、SocketTool 1、TCP 通信测试: 1)创建 TCP Server 2)创建 TCP Client 连接 Socket 4)数据收发 在TCP Server发送数据12345 在 TCP Client 端的 Socket 即可收到数据12…

2026/7/4 16:14:43 阅读更多 →

最新新闻

位置编码外推实战:从BERT 512到26万token的3种延拓策略

位置编码外推实战:从BERT 512到26万token的3种延拓策略

位置编码外推实战:从BERT 512到26万token的3种延拓策略当处理长文本序列时,BERT等Transformer模型面临一个根本性限制——位置编码的长度约束。传统BERT模型最多只能处理512个token,这严重制约了其在长文档理解、基因组分析等场景的应用潜力。…

2026/7/6 0:11:20 阅读更多 →
如何彻底告别重复点击:AutoClicker鼠标自动化完全指南

如何彻底告别重复点击:AutoClicker鼠标自动化完全指南

如何彻底告别重复点击:AutoClicker鼠标自动化完全指南 【免费下载链接】AutoClicker AutoClicker is a useful simple tool for automating mouse clicks. 项目地址: https://gitcode.com/gh_mirrors/au/AutoClicker 还在为每天重复的鼠标点击任务感到疲惫吗…

2026/7/6 0:11:20 阅读更多 →
DQN 算法实战:CartPole-v0 环境 1000 轮训练实现 200 分满分

DQN 算法实战:CartPole-v0 环境 1000 轮训练实现 200 分满分

DQN算法实战:从零构建CartPole智能体的完整指南1. 环境准备与基础概念在开始构建DQN智能体之前,我们需要先理解几个核心概念。CartPole-v0是OpenAI Gym中的一个经典控制问题,目标是让小车上的杆子保持直立不倒下。这个环境有四个状态变量&…

2026/7/6 0:11:20 阅读更多 →
OpenCV 4.8 双目立体匹配实战:BM/SGBM/GC 3种算法在Middlebury数据集上的精度与速度对比

OpenCV 4.8 双目立体匹配实战:BM/SGBM/GC 3种算法在Middlebury数据集上的精度与速度对比

OpenCV 4.8 双目立体匹配实战:BM/SGBM/GC算法在Middlebury数据集上的精度与速度对比双目立体视觉作为三维重建的核心技术之一,其核心挑战在于如何高效准确地计算左右图像间的视差图。OpenCV作为计算机视觉领域的瑞士军刀,提供了Block Matchin…

2026/7/6 0:07:19 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻