分布式專題——10.4 ShardingSphere-Proxy服務端分庫分表

1 為什么要有服務端分庫分表?

  • ShardingSphere-Proxy 是 ShardingSphere 提供的服務端分庫分表工具,定位是“透明化的數據庫代理”。

    • 它模擬 MySQL 或 PostgreSQL 的數據庫服務,應用程序(Application)只需像訪問單個數據庫一樣訪問 ShardingSphere-Proxy;

    • 實際的分庫分表邏輯,由 ShardingSphere-Proxy 在代理層完成,對應用程序完全透明;

      在這里插入圖片描述

  • ShardingSphere-JDBC 已經能實現分庫分表,為什么還需要 ShardingSphere-Proxy?

    • 對 ORM 框架更友好

      • ShardingSphere-JDBC 的問題:需要在業務代碼中直接寫分庫分表邏輯(比如代碼里寫:數據該路由到哪個庫/表)。如果項目用了 ORM 框架(如 MyBatis、Hibernate),這種代碼侵入式的邏輯容易和 ORM 沖突;

      • ShardingSphere-Proxy 的解決:作為第三方服務端代理,分庫分表邏輯在代理層(ShardingSphere-Proxy)處理,應用程序完全不用關心。應用只需按訪問單庫的方式寫代碼,無縫對接 ORM 框架;

    • 對 DBA(數據庫管理員)更友好

      • ShardingSphere-JDBC 的問題:DBA 要管理分庫分表后的數據庫,得先了解 ShardingSphere 的專屬功能和 API,學習成本高;

      • ShardingSphere-Proxy 的解決:對 DBA 完全透明。DBA 可以直接操作原始數據庫(像平時管理 MySQL/PostgreSQL 一樣),無需了解 ShardingSphere 的技術細節,簡化了 DBA 的工作;

    • 避免業務代碼侵入分庫分表邏輯

      • ShardingSphere-JDBC 的問題:分庫分表的規則配置(比如“按用戶 ID 分庫”的規則)要寫在業務代碼里,會讓業務代碼變得臃腫。如果規則變更(比如從“按用戶 ID 分”改成“按訂單 ID 分”),要修改大量業務代碼,維護成本高;

      • ShardingSphere-Proxy 的解決:通過外部配置文件管理分庫分表規則,業務代碼完全不用關心這些邏輯。規則變更時,只需改配置,不影響業務代碼;

    • 實現“無中心化”數據治理

      • ShardingSphere-JDBC 的局限:多數據源的治理(比如跨庫監控、報警、統一管理)難以統一;

      • ShardingSphere-Proxy 的解決:多個數據源可以注冊到同一個 ShardingSphere-Proxy 代理服務中。基于代理,能實現跨數據源的數據治理(比如統一監控、報警、數據管理),特別適合大規模微服務系統的運維。

2 基本使用

2.1 部署 ShardingSphere-Proxy

  • 下載并解壓(注意不要有中文,此處選擇的版本:Apache Archive Distribution Directory);

    在這里插入圖片描述

  • ShardingSphere-Proxy 是一個典型的 Java 應用程序,解壓后目錄結構如下:

    在這里插入圖片描述

  • 解壓完成后,如果要連接 MySQL 數據庫,那么需要手動將 JDBC 的驅動包mysql-connector-java-8.0.20.jar復制到 ShardingSphere-Proxy 的lib目錄下(ShardingSphere-Proxy 默認只附帶了 PostgreSQL 的 JDBC 驅動包,沒有包含 MySQL 的 JDBC 驅動包);

  • 打開conf目錄,在這個目錄下就有 ShardingSphere-Proxy 的所有配置文件(不同版本的會不一樣):

    在這里插入圖片描述

  • 打開server.yaml,把其中的rules部分和props部分的注釋取消:

    rules:# 權限控制規則配置- !AUTHORITYusers:# 定義用戶權限:root用戶可從任何主機(%)訪問,擁有root角色;sharding用戶可從任何主機訪問,擁有sharding角色- root@%:root- sharding@:shardingprovider:# 權限提供者類型:ALL_PERMITTED表示允許所有操作(無權限限制)type: ALL_PERMITTED# 事務管理配置- !TRANSACTION# 默認事務類型:XA分布式事務defaultType: XA# 事務管理器提供者:Atomikos(一種XA事務管理器實現)providerType: Atomikos# SQL解析器配置- !SQL_PARSER# 啟用SQL注釋解析功能sqlCommentParseEnabled: truesqlStatementCache:# SQL語句緩存初始容量initialCapacity: 2000# SQL語句緩存最大容量maximumSize: 65535parseTreeCache:# 解析樹緩存初始容量initialCapacity: 128# 解析樹緩存最大容量maximumSize: 1024# 屬性配置
    props:# 每個查詢允許的最大連接數max-connections-size-per-query: 1# 內核線程池大小(默認無限制)kernel-executor-size: 16# 代理前端刷新閾值(網絡數據包刷新條件)proxy-frontend-flush-threshold: 128# 是否啟用Hint功能(強制路由提示)proxy-hint-enabled: false# 是否在日志中顯示SQL語句sql-show: false# 是否啟用表元數據一致性檢查check-table-metadata-enabled: false# 代理后端查詢獲取大小:-1表示使用不同JDBC驅動程序的最小值proxy-backend-query-fetch-size: -1# 代理前端執行線程數:0表示由Netty自動決定proxy-frontend-executor-size: # 代理后端執行模式:OLAP(聯機分析處理)或OLTP(聯機事務處理)proxy-backend-executor-suitable: OLAP# 代理前端最大連接數:0或負數表示無限制proxy-frontend-max-connections: 0# SQL聯邦查詢類型:NONE(禁用),ORIGINAL(原始),ADVANCED(高級)sql-federation-type: NONE# 代理后端驅動類型:JDBC(標準)或ExperimentalVertx(實驗性Vert.x)proxy-backend-driver-type: JDBC# 默認MySQL版本號(當缺少schema信息時使用)proxy-mysql-default-version: 8.0.20# 代理服務默認端口proxy-default-port: 3307# Netty網絡連接后備隊列長度proxy-netty-backlog: 1024
    
    • 注意:為了與 MySQL JDBC 的驅動包mysql-connector-java-8.0.20.jar兼容,將proxy-mysql-default-version修改為8.0.20
  • 啟動:

    在這里插入圖片描述

  • 然后就可以使用 MySQL 的客戶端(比如 DataGrip)去連接 ShardingSphere-Proxy 了,且可以像用 MySQL 一樣去使用 ShardingSphere-Proxy:

    mysql> show databases;
    +--------------------+
    | schema_name        |
    +--------------------+
    | shardingsphere     |
    | information_schema |
    | performance_schema |
    | mysql              |
    | sys                |
    +--------------------+
    5 rows in set (0.01 sec)mysql> use shardingsphere
    Database changed
    mysql> show tables;
    +---------------------------+------------+
    | Tables_in_shardingsphere  | Table_type |
    +---------------------------+------------+
    | sharding_table_statistics | BASE TABLE |
    +---------------------------+------------+
    1 row in set (0.01 sec)mysql> select * from sharding_table_statistics;
    Empty set (1.25 sec)
    
  • 不過要注意,此時 ShardingSphere-Proxy 只是一個虛擬庫,所以并不能像 MySQL 一樣去隨意建表或修改數據,比如下面就建表失敗:

    mysql> CREATE TABLE test  (id varchar(255) NOT NULL);
    Query OK, 0 rows affected (0.00 sec)mysql> select * from test;
    30000 - Unknown exception: At line 0, column 0: Object 'test' not found
    mysql> show tables;
    +---------------------------+------------+
    | Tables_in_shardingsphere  | Table_type |
    +---------------------------+------------+
    | sharding_table_statistics | BASE TABLE |
    +---------------------------+------------+
    1 row in set (0.01 sec)
    

2.2 常用的分庫分表配置策略

  • 打開config-sharding.yaml,配置邏輯表course

    # 邏輯數據庫名稱(客戶端連接時使用的虛擬數據庫名)
    databaseName: sharding_db# 數據源配置(定義實際的后端數據庫連接)
    dataSources:# 第一個數據源,命名為m0m0:# MySQL數據庫連接URL,指向192.168.65.212服務器的3306端口,數據庫名為shardingdb1url: jdbc:mysql://192.168.65.212:3306/shardingdb1?serverTimezone=UTC&useSSL=falseusername: rootpassword: root# 連接超時時間(毫秒)connectionTimeoutMilliseconds: 30000# 連接空閑超時時間(毫秒)idleTimeoutMilliseconds: 60000# 連接最大生命周期(毫秒)maxLifetimeMilliseconds: 1800000# 連接池最大大小maxPoolSize: 50# 連接池最小大小minPoolSize: 1# 第二個數據源,命名為m1m1:url: jdbc:mysql://192.168.65.212:3306/shardingdb2?serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1# 分片規則配置
    rules:
    - !SHARDING  # 分片規則標識tables:# 配置course表的分片規則course:# 實際數據節點:分布在m0和m1數據庫的course_1和course_2表中actualDataNodes: m${0..1}.course_${1..2}# 數據庫分片策略databaseStrategy:standard:  # 標準分片策略shardingColumn: cid  # 分片列(根據此字段的值決定數據路由到哪個數據庫)shardingAlgorithmName: course_db_alg  # 使用的分片算法名稱# 表分片策略tableStrategy:standard:  # 標準分片策略shardingColumn: cid  # 分片列(根據此字段的值決定數據路由到哪個表)shardingAlgorithmName: course_tbl_alg  # 使用的分片算法名稱# 主鍵生成策略keyGenerateStrategy:column: cid  # 需要生成主鍵的列名keyGeneratorName: alg_snowflake  # 使用的主鍵生成器名稱# 分片算法定義shardingAlgorithms:# 數據庫分片算法:取模算法course_db_alg:type: MOD  # 取模分片算法props:sharding-count: 2  # 分片數量(2個數據庫)# 表分片算法:行表達式算法course_tbl_alg:type: INLINE  # 行表達式分片算法props:# 算法表達式:根據cid字段的值取模2再加1,得到表后綴(1或2)algorithm-expression: course_${cid%2+1}# 主鍵生成器定義keyGenerators:# 雪花算法生成器,用于生成分布式唯一IDalg_snowflake:type: SNOWFLAKE  # 使用雪花算法
    
  • 重新啟動 ShardingSphere-Proxy 服務:

    mysql> show databases;
    +--------------------+
    | schema_name        |
    +--------------------+
    | information_schema |
    | performance_schema |
    | sys                |
    | shardingsphere     |
    | sharding_db        |
    | mysql              |
    +--------------------+
    6 rows in set (0.02 sec)mysql> use sharding_db;
    Database changed
    mysql> show tables;
    +-----------------------+------------+
    | Tables_in_sharding_db | Table_type |
    +-----------------------+------------+
    | course                | BASE TABLE |
    | user_2                | BASE TABLE |
    | user                  | BASE TABLE |
    | user_1                | BASE TABLE |
    +-----------------------+------------+
    4 rows in set (0.02 sec)mysql> select * from course;
    +---------------------+-------+---------+---------+
    | cid                 | cname | user_id | cstatus |
    +---------------------+-------+---------+---------+
    | 1017125767709982720 | java  |    1001 | 1       |
    | 1017125769383510016 | java  |    1001 | 1       |mysql> select * from course_1;
    +---------------------+-------+---------+---------+
    | cid                 | cname | user_id | cstatus |
    +---------------------+-------+---------+---------+
    | 1017125767709982720 | java  |    1001 | 1       |
    | 1017125769383510016 | java  |    1001 | 1       |
    
    • 可以看到多了一個sharding_db庫。

3 ShardingSphere-Proxy 中的分布式事務機制

3.1 為什么需要分布式事務?

  • XA 事務 :: ShardingSphere;

  • 2.1 部署 ShardingSphere-Proxy中配置server.yaml時,有一個TRANSACTION配置項:

    rules:
    - !TRANSACTIONdefaultType: XAproviderType: Atomikos
    
  • 為什么 ShardingSphere-Proxy 需要分布式事務?

    • ShardingSphere(尤其是 ShardingSphere-Proxy)要操作分布式的數據庫集群(多個庫、多個節點)。而數據庫的本地事務只能保證單個數據庫內的事務安全,無法覆蓋跨多個數據庫的場景;

    • 因此,必須引入分布式事務管理機制,才能保證 ShardingSphere-Proxy 中 SQL 執行的原子性。開啟分布式事務后,開發者不用再手動考慮跨庫 SQL 的事務問題。

3.2 什么是 XA 事務?

  • XA 是由 X/Open Group 組織定義的分布式事務標準,主流關系型數據庫(如 MySQL、Oracle 等)都實現了 XA 協議(比如 MySQL 5.0.3+ 的 InnoDB 引擎支持 XA);

  • XA 事務的核心是兩階段提交(2PC),通過**準備(Prepare)提交(Commit)**兩個階段,保證跨多個數據庫的事務一致性;

  • XA 分布式事務操作示例:

    -- 1. 開啟XA事務,'test'是事務標識符(XID),將事務狀態設置為ACTIVE(活躍)
    -- 事務標識符用于在分布式環境中唯一標識一個事務
    XA START 'test';-- 2. 在ACTIVE狀態的XA事務中執行業務SQL語句
    -- 這些操作是事務的一部分,但尚未最終提交
    INSERT INTO dict VALUES(1, 't', 'test');-- 3. 結束XA事務,將事務狀態從ACTIVE改為IDLE(空閑)
    -- 表示事務內的所有操作已完成,準備進入準備階段
    XA END 'test';-- 4. 準備提交事務,將事務狀態從IDLE改為PREPARED(已準備)
    -- 此階段事務管理器會確保所有資源管理器都已準備好提交
    XA PREPARE 'test';-- 5. 列出所有處于PREPARED狀態的XA事務
    -- 返回的信息包含:gtrid(全局事務ID)、bqual(分支限定符)、formatID(格式ID)和data(數據)
    XA RECOVER;-- 6. 提交已準備的XA事務,使所有更改永久生效
    -- 這是兩階段提交的第二階段(提交階段)
    XA COMMIT 'test';-- 6. 替代方案:回滾已準備的XA事務,撤銷所有更改
    -- 在PREPARED狀態下也可以選擇回滾而不是提交
    XA ROLLBACK 'test';-- 注意:也可以使用單條命令直接提交,將預備和提交合并操作
    -- XA COMMIT 'test' ONE PHASE;
    
  • ShardingSphere 集成了多個 XA 實現框架(Atomikos、Bitronix、Narayana)。在 ShardingSphere-Proxy 中,默認只集成了 Atomikos(所以配置里 providerType: Atomikos)。

3.3 實戰理解 XA 事務

  • 引入 Maven 依賴:

    <dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-transaction-xa-core</artifactId><version>5.2.1</version><exclusions><exclusion><artifactId>transactions-jdbc</artifactId><groupId>com.atomikos</groupId></exclusion><exclusion><artifactId>transactions-jta</artifactId><groupId>com.atomikos</groupId></exclusion></exclusions>
    </dependency>
    <!-- 版本滯后了 -->
    <dependency><artifactId>transactions-jdbc</artifactId><groupId>com.atomikos</groupId><version>5.0.8</version>
    </dependency>
    <dependency><artifactId>transactions-jta</artifactId><groupId>com.atomikos</groupId><version>5.0.8</version>
    </dependency>
    <!-- 使用XA事務時,可以引入其他幾種事務管理器 -->
    <!--        <dependency>-->
    <!--            <groupId>org.apache.shardingsphere</groupId>-->
    <!--            <artifactId>shardingsphere-transaction-xa-bitronix</artifactId>-->
    <!--            <version>5.2.1</version>-->
    <!--        </dependency>-->
    <!--        <dependency>-->
    <!--            <groupId>org.apache.shardingsphere</groupId>-->
    <!--            <artifactId>shardingsphere-transaction-xa-narayana</artifactId>-->
    <!--            <version>5.2.1</version>-->
    <!--        </dependency>-->
    
  • 配置事務管理器:

    @Configuration
    @EnableTransactionManagement
    public class TransactionConfiguration {@Beanpublic PlatformTransactionManager txManager(final DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
    }
    
  • 測試案例:

    public class MySQLXAConnectionTest {public static void main(String[] args) throws SQLException {// 是否打印XA相關命令,用于調試目的boolean logXaCommands = true;// ============== 初始化階段:建立數據庫連接 ==============// 獲取第一個數據庫連接(資源管理器RM1)Connection conn1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC", "root", "root");// 創建XA連接包裝器,用于支持分布式事務XAConnection xaConn1 = new MysqlXAConnection((com.mysql.cj.jdbc.JdbcConnection) conn1, logXaCommands);// 獲取XA資源接口,用于控制分布式事務XAResource rm1 = xaConn1.getXAResource();// 獲取第二個數據庫連接(資源管理器RM2)Connection conn2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC", "root", "root");// 創建第二個XA連接包裝器XAConnection xaConn2 = new MysqlXAConnection((com.mysql.cj.jdbc.JdbcConnection) conn2, logXaCommands);// 獲取第二個XA資源接口XAResource rm2 = xaConn2.getXAResource();// 生成全局事務ID(GTrid,是全局事務標識符,在整個事務生命周期中唯一)byte[] gtrid = "g12345".getBytes();int formatId = 1; // 格式標識符,通常為1,表示標準XID格式try {// ============== 分別執行RM1和RM2上的事務分支 ====================// 為第一個資源管理器生成分支事務ID(BQual)byte[] bqual1 = "b00001".getBytes();// 創建完整的事務ID(XID),包含全局ID和分支IDXid xid1 = new MysqlXid(gtrid, bqual1, formatId);// 開始第一個分支事務,TMNOFLAGS表示新建一個事務(不是加入或恢復現有事務)rm1.start(xid1, XAResource.TMNOFLAGS);// 在第一個分支事務中執行SQL操作PreparedStatement ps1 = conn1.prepareStatement("INSERT INTO `dict` VALUES (1, 'T', '測試1');");ps1.execute();// 結束第一個分支事務,TMSUCCESS表示事務執行成功rm1.end(xid1, XAResource.TMSUCCESS);// 為第二個資源管理器生成分支事務IDbyte[] bqual2 = "b00002".getBytes();// 創建第二個事務IDXid xid2 = new MysqlXid(gtrid, bqual2, formatId);// 開始第二個分支事務rm2.start(xid2, XAResource.TMNOFLAGS);// 在第二個分支事務中執行SQL操作PreparedStatement ps2 = conn2.prepareStatement("INSERT INTO `dict` VALUES (2, 'F', '測試2');");ps2.execute();// 結束第二個分支事務rm2.end(xid2, XAResource.TMSUCCESS);// =================== 兩階段提交流程 ============================// 第一階段:準備階段 - 詢問所有資源管理器是否準備好提交事務int rm1_prepare = rm1.prepare(xid1);int rm2_prepare = rm2.prepare(xid2);// 第二階段:提交階段 - 根據準備階段的結果決定提交或回滾boolean onePhase = false; // 設置為false表示使用標準的兩階段提交// 檢查所有資源管理器是否都準備成功if (rm1_prepare == XAResource.XA_OK&& rm2_prepare == XAResource.XA_OK) {// 所有分支都準備成功,提交所有事務rm1.commit(xid1, onePhase);rm2.commit(xid2, onePhase);} else {// 如果有任何一個分支準備失敗,回滾所有事務rm1.rollback(xid1);rm2.rollback(xid2);}} catch (XAException e) {// 處理XA異常,打印異常信息e.printStackTrace();}}
    }
    
  • XA標準規范了事務XID的格式,它由三個部分組成:gtrid [, bqual [, formatID ]],具體含義如下:

    • gtrid(全局事務標識符)

      • global transaction identifier,是用于標識一個全局事務的唯一值 。在分布式事務場景下,多個數據庫節點參與同一個事務,通過這個全局事務標識符可以將這些操作關聯到一起,明確它們屬于同一個事務;
      • 比如在一個涉及電商系統多個數據庫(訂單庫、庫存庫、支付庫)的分布式事務中,通過相同的gtrid就能確認這些數據庫上的操作都屬于同一次購物流程對應的事務;
    • bqual(分支限定符)

      • branch qualifier ,用來進一步限定事務分支。如果沒有提供,會使用默認值即一個空字符串;
      • 例如,在一個分布式事務中有多個數據庫節點,每個節點上的操作可以看作事務的一個分支,bqual 就可以用來區分和標識這些不同的分支,以便更精確地管理事務在各個節點上的執行情況;
    • formatID(格式標識符)

      • 是一個數字,用于標記gtrid和bqual值的格式,是一個正整數,最小為0,默認值是1 ;
      • 它主要用于在不同的系統或數據庫之間進行交互時,明確全局事務標識符和分支限定符的格式規則,以確保各方能夠正確解析和處理事務標識信息。
  • 使用XA事務時的注意事項

    • 無法自動提交:與本地事務在滿足一定條件下可以自動提交不同,XA事務需要開發者顯式地調用提交指令(如XA COMMIT) 。這就要求開發者在編寫代碼時,要準確把控事務提交的時機,避免因疏忽未提交事務而導致數據不一致等問題。例如在編寫一個涉及多個數據庫操作的業務邏輯時,開發者需要在所有操作都成功執行后,手動調用提交語句來完成事務,否則事務會一直處于未提交狀態;

    • 效率低下:XA事務執行效率遠低于本地事務,通常耗時能達到本地事務的10倍。這是因為在XA事務中,全局事務的狀態都需要持久化,涉及到多個數據庫節點之間的協調和通信,比如在兩階段提交過程中,準備階段各個節點要記錄事務狀態等信息,提交階段又需要進行多次確認和交互,這些額外的操作增加了系統開銷,降低了事務處理的速度。這就意味著在對性能要求極高的場景中,使用XA事務可能并不合適,需要謹慎評估;

    • 故障隔離困難:在XA事務提交前如果出現故障(如某個數據庫節點宕機、網絡中斷等),很難將問題隔離開 。由于XA事務涉及多個數據庫節點的協同工作,一個節點出現故障可能會影響到整個事務的執行,而且故障排查和恢復相對復雜。例如在一個跨地域的分布式數據庫系統中,如果某個地區的數據庫節點在XA事務準備階段出現故障,不僅要處理該節點自身的數據恢復問題,還要協調其他節點來處理事務狀態,以保證整個系統的數據一致性。

3.4 如何在 ShardingSphere-Proxy 中使用其他事務管理器?

  • ShardingSphere-Proxy 支持多種分布式事務管理器(如 Atomikos、Narayana、Bitronix)。默認集成的是 Atomikos,若要改用其它兩種事務管理器,需手動配置;

  • 具體操作(以 Narayana 為例)

    • 添加 Narayana 的依賴包:

      • 將 Narayana 事務集成的 Jar 包(如 shardingsphere-transaction-xa-narayana-5.2.1.jar),放到 ShardingSphere-Proxy 的 lib 目錄下;
      • 該 Jar 包可通過 Maven 依賴下載(需要在項目的 Maven 配置中引入對應依賴,構建后獲取 Jar 包);
    • server.yamlrules 部分,將事務的 providerType 配置為 Narayana。配置示例:

      rules:- !TRANSACTIONdefaultType: XAproviderType: Narayana
      
  • 注意事項:ShardingSphere 版本更新快,部分依賴可能未及時維護,存在組件版本沖突的風險。使用前需確認依賴包與 ShardingSphere-Proxy 版本的兼容性。

4 ShardingSphere-Proxy 集群化部署

4.1 ShardingSphere-Proxy 的運行模式

  • server.yaml 文件中,有一段被注釋的 mode 配置。這段配置的作用是指定 ShardingSphere 的運行模式,決定 ShardingSphere 如何管理復雜的配置信息:

    #mode:
    #  type: Cluster
    #  repository:
    #    type: ZooKeeper
    #    props:
    #      namespace: governance_ds
    #      server-lists: localhost:2181
    #      retryIntervalMilliseconds: 500
    #      timeToLiveSeconds: 60
    #      maxRetries: 3
    #      operationTimeoutMilliseconds: 500
    
  • ShardingSphere 支持 Standalone(獨立模式)Cluster(集群模式) 兩種運行模式,核心差異如下:

    • Standalone(獨立模式)

      • ShardingSphere 不需要考慮其他實例的影響,直接在內存中管理核心配置規則

      • 是 ShardingSphere 默認的運行模式,配置簡單,無需依賴第三方組件。

      • 適用場景:小型項目,或對性能要求較高的場景(因為沒有額外的配置同步開銷)。通常配合 ShardingJDBC 使用(ShardingJDBC 是客戶端分庫分表,更側重性能);

    • Cluster(集群模式)

      • ShardingSphere 不僅要管理自身配置,還要與集群中其他實例同步配置規則。因此需要引入第三方配置中心(如 Zookeeper、etcd、Nacos 等)來實現配置同步;

      • 推薦的配置中心:在分庫分表場景下,配置信息變動少、訪問頻率低,因此基于 CP 架構的 Zookeeper 最推薦(CP 架構保證數據一致性,適合配置這類強一致需求的場景);

      • 優先級:如果應用本地和 Zookeeper 都有配置,ShardingSphere 以 Zookeeper 中的配置為準(保證集群配置統一);

      • 適用場景:大規模集群環境,需要多實例協同工作,通常配合 ShardingSphere-Proxy 使用;

  • 模式選擇建議

    • Standalone:小型項目、性能敏感場景 → 配合 ShardingJDBC;

    • Cluster:大規模集群環境 → 配合 ShardingSphere-Proxy,且推薦用 Zookeeper 作為配置中心。

4.2 使用 Zookeeper 進行集群部署

  • 接下來基于 Zookeeper 部署一下 ShardingSphere-Proxy 集群;

  • 首先在本地部署一個 Zookeeper,然后將server.yaml中的mode部分解除注釋:

    # ShardingSphere 運行模式配置
    mode:# 運行模式類型:Cluster 表示集群模式(支持多個Proxy實例組成集群)type: Cluster# 集群元數據存儲倉庫配置repository:# 倉庫類型:ZooKeeper(使用ZooKeeper作為分布式協調服務)type: ZooKeeper# ZooKeeper連接配置屬性props:# ZooKeeper命名空間:用于在ZooKeeper中隔離不同環境的配置namespace: governance_ds# ZooKeeper服務器地址列表:支持多個服務器地址,用逗號分隔server-lists: 192.168.65.212:2181# 重試間隔時間(毫秒):連接失敗后重試的等待時間retryIntervalMilliseconds: 500# 節點存活時間(秒):在ZooKeeper中創建的臨時節點的存活時間timeToLiveSeconds: 60# 最大重試次數:連接ZooKeeper失敗時的最大重試次數maxRetries: 3# 操作超時時間(毫秒):ZooKeeper操作(如創建、讀取節點)的超時時間operationTimeoutMilliseconds: 500
    
  • 啟動 ShardingSphere-Proxy 服務,在 Zookeeper 注冊中心可以看到 ShardingSphere 集群模式下的節點結構如下:

    # ShardingSphere 集群模式下的 ZooKeeper 節點結構詳解# 根命名空間(用于環境隔離,避免不同環境配置相互干擾)
    namespace: governance_ds
    # 全局配置節點
    ├── rules                    # 存儲全局規則配置(如分片規則、加密規則等)
    ├── props                    # 存儲全局屬性配置(如SQL顯示開關、執行模式等)
    # 元數據管理節點
    ├── metadata                 # 元數據配置根目錄
    │   ├── ${databaseName}      # 邏輯數據庫名稱(如:sharding_db)
    │   │   ├── schemas          # 邏輯Schema列表
    │   │   │   ├── ${schemaName} # 邏輯Schema名稱
    │   │   │   │   ├── tables   # 表結構配置
    │   │   │   │   │   ├── ${tableName}  # 具體表的結構定義
    │   │   │   │   │   └── ...  # 其他表
    │   │   │   │   └── views    # 視圖結構配置
    │   │   │   │       ├── ${viewName}   # 具體視圖的定義
    │   │   │   │       └── ...  # 其他視圖
    │   │   │   └── ...          # 其他Schema
    │   │   └── versions         # 元數據版本管理
    │   │       ├── ${versionNumber} # 具體版本號(如:v1, v2)
    │   │       │   ├── dataSources # 該版本的數據源配置
    │   │       │   └── rules       # 該版本的規則配置
    │   │       ├── active_version  # 當前激活的元數據版本號
    │   │       └── ...          # 其他版本
    # 計算節點管理(Proxy和JDBC實例管理)
    ├── nodes
    │   ├── compute_nodes        # 計算節點管理根目錄
    │   │   ├── online           # 在線實例列表
    │   │   │   ├── proxy        # Proxy模式實例
    │   │   │   │   ├── UUID     # 每個Proxy實例的唯一標識(如:生成的實際UUID)
    │   │   │   │   └── ...      # 其他Proxy實例
    │   │   │   └── jdbc         # JDBC模式實例
    │   │   │       ├── UUID     # 每個JDBC實例的唯一標識
    │   │   │       └── ...      # 其他JDBC實例
    │   │   ├── status           # 實例狀態信息
    │   │   │   ├── UUID         # 具體實例的狀態數據
    │   │   │   └── ...          # 其他實例狀態
    │   │   ├── worker_id        # 工作節點ID分配
    │   │   │   ├── UUID         # 實例分配的工作ID
    │   │   │   └── ...          # 其他實例的工作ID
    │   │   ├── process_trigger  # 進程觸發管理
    │   │   │   ├── process_list_id:UUID  # 進程列表與實例的關聯
    │   │   │   └── ...          # 其他進程觸發信息
    │   │   └── labels           # 實例標簽管理
    │   │       ├── UUID         # 具體實例的標簽配置
    │   │       └── ...          # 其他實例標簽
    # 存儲節點管理(實際數據源管理)
    │   └── storage_nodes        # 存儲節點管理根目錄
    │       ├── ${databaseName.groupName.ds}  # 數據源節點命名格式:邏輯庫名.組名.數據源名
    │       └── ${databaseName.groupName.ds}  # 另一個數據源節點
    
  • server.yaml中的rules部分同2.1 部署 ShardingSphere-Proxy

  • 分庫分表配置同2.2 常用的分庫分表配置策略

4.3 統一 JDBC 和 Proxy 配置信息

  • ShardingSphere-JDBC 也能像 ShardingSphere-Proxy 一樣,通過 Zookeeper 同步配置信息,從而實現兩者配置的統一管理(減少配置分散,便于集群化維護)。

4.3.1 通過注冊中心同步配置

  • application.properties 中,刪除之前 ShardingSphere-JDBC 相關的分庫分表規則等配置,只配置Zookeeper 的連接和集群模式。示例配置:

    # 指定運行模式為“集群模式(Cluster)”
    spring.shardingsphere.mode.type=Cluster
    # 指定配置中心類型為 Zookeeper
    spring.shardingsphere.mode.repository.type=Zookeeper
    # Zookeeper 的命名空間(用于隔離不同配置,自定義即可)
    spring.shardingsphere.mode.repository.props.namespace=governance_ds
    # Zookeeper 的地址和端口
    spring.shardingsphere.mode.repository.props.server-lists=localhost:2181
    # 重試間隔(毫秒)
    spring.shardingsphere.mode.repository.props.retryIntervalMilliseconds=600
    # 存活時間(秒)
    spring.shardingsphere.mode.repository.props.timeToLiveSeconds=60
    # 最大重試次數
    spring.shardingsphere.mode.repository.props.maxRetries=3
    # 操作超時時間(毫秒)
    spring.shardingsphere.mode.repository.props.operationTimeoutMilliseconds=500
    
  • 配置完成后,可繼續驗證對表(如 course 表)的分庫分表操作,此時 ShardingSphere-JDBC 會從 Zookeeper 中拉取配置信息來執行分庫分表邏輯;

  • 注意:

    • 如果在 ShardingSphere-JDBC 中讀取配置中心(Zookeeper)的配置,需要用 spring.shardingsphere.database.name 指定對應的虛擬庫
    • 若不配置該參數,默認值為 logic_db
    • 這個虛擬庫是 ShardingSphere 中邏輯上的數據庫概念,用于統一管理分庫分表后的邏輯結構。

4.3.2 使用ShardingSphere-Proxy提供的JDBC驅動讀取配置文件

  • ShardingSphere 過去是通過兼容 MySQL 或 PostgreSQL 服務的方式,提供分庫分表功能:

    • 應用端需要用 MySQL/PostgreSQL 的 JDBC 驅動,去訪問 ShardingSphere 封裝的數據源(ShardingSphereDataSource);

    • 這種方式相當于模擬成 MySQL/PostgreSQL 數據庫,讓應用無感知地使用分庫分表能力,但依賴的是第三方數據庫的 JDBC 驅動;

  • 在當前版本中,ShardingSphere 直接提供了自己的 JDBC 驅動

    • 這意味著應用可以不再依賴 MySQL/PostgreSQL 的 JDBC 驅動,直接用 ShardingSphere 專屬的驅動來連接和操作數據;

    • 優勢是更原生、更直接地支持 ShardingSphere 的特性(分庫分表、分布式事務等),減少對第三方驅動的依賴,也能更靈活地擴展功能;

  • 比如在 ShardingSphere-JDBC 中,可在類路徑(classpath)下增加 config.yaml 文件,將之前 ShardingSphere-Proxy中的關鍵配置整合到這個文件中。這樣 ShardingSphere-JDBC 就能通過自身的 JDBC 驅動,讀取 config.yaml 里的配置(分庫分表規則、數據源等),實現和 ShardingSphere-Proxy 類似的分庫分表邏輯:

    rules:- !AUTHORITYusers:- root@%:root- sharding@:shardingprovider:type: ALL_PERMITTED- !TRANSACTIONdefaultType: XAproviderType: Atomikos- !SQL_PARSERsqlCommentParseEnabled: truesqlStatementCache:initialCapacity: 2000maximumSize: 65535parseTreeCache:initialCapacity: 128maximumSize: 1024- !SHARDINGtables:course:actualDataNodes: m${0..1}.course_${1..2}databaseStrategy:standard:shardingColumn: cidshardingAlgorithmName: course_db_algtableStrategy:standard:shardingColumn: cidshardingAlgorithmName: course_tbl_algkeyGenerateStrategy:column: cidkeyGeneratorName: alg_snowflakeshardingAlgorithms:course_db_alg:type: MODprops:sharding-count: 2course_tbl_alg:type: INLINEprops:algorithm-expression: course_$->{cid%2+1}keyGenerators:alg_snowflake:type: SNOWFLAKEprops:max-connections-size-per-query: 1kernel-executor-size: 16proxy-frontend-flush-threshold: 128proxy-hint-enabled: falsesql-show: falsecheck-table-metadata-enabled: falseproxy-backend-query-fetch-size: -1proxy-frontend-executor-size: 0proxy-backend-executor-suitable: OLAPproxy-frontend-max-connections: 0 sql-federation-type: NONEproxy-backend-driver-type: JDBCproxy-mysql-default-version: 8.0.20proxy-default-port: 3307proxy-netty-backlog: 1024databaseName: sharding_db
    dataSources:m0:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://127.0.0.1:3306/coursedb?serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1m1:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://127.0.0.1:3306/coursedb2?serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1
    
  • 然后,可以直接用 JDBC 的方式訪問帶有分庫分表的虛擬庫:

    public class ShardingJDBCDriverTest {@Testpublic void test() throws ClassNotFoundException, SQLException {// 定義ShardingSphere JDBC驅動類全限定名// 這是ShardingSphere提供的專用JDBC驅動,用于攔截和路由SQL請求String jdbcDriver = "org.apache.shardingsphere.driver.ShardingSphereDriver";// JDBC連接URL,指定使用ShardingSphere驅動和配置文件路徑// classpath:config.yaml 表示配置文件位于類路徑下的config.yaml文件String jdbcUrl = "jdbc:shardingsphere:classpath:config.yaml";// 要執行的SQL查詢語句// 這里查詢的是邏輯數據庫sharding_db中的course表// ShardingSphere會根據配置將查詢路由到實際的物理表String sql = "select * from sharding_db.course";// 加載ShardingSphere JDBC驅動類// 這是使用JDBC驅動的標準方式,驅動會自動注冊到DriverManagerClass.forName(jdbcDriver);// 使用try-with-resources語句確保連接正確關閉try(Connection connection = DriverManager.getConnection(jdbcUrl);) {// 創建Statement對象用于執行SQL語句Statement statement = connection.createStatement();// 執行SQL查詢并返回ResultSet結果集// ShardingSphere會在此處攔截SQL,根據分片規則路由到正確的數據節點ResultSet resultSet = statement.executeQuery(sql);// 遍歷結果集,處理查詢結果while (resultSet.next()){// 從結果集中獲取cid字段的值并輸出// ShardingSphere會自動合并來自多個分片的結果System.out.println("course cid= "+resultSet.getLong("cid"));}// try-with-resources會自動關閉statement和resultSet}// try-with-resources會自動關閉connection,釋放數據庫連接資源}
    }
    
  • 官方的說明是 ShardingSphereDriver 讀取config.yaml時, 這個config.yaml配置信息與 ShardingSphere-Proxy 中的配置文件完全是相同的,甚至可以直接將 ShardingSphere-Proxy 中的配置文件拿過來用。但是從目前版本來看,還是有不少小問題的,靜待后續版本跟蹤吧;

  • 到這里,對于之前講解過的 ShardingSphere 的混合架構,有沒有更新的了解?

    在這里插入圖片描述

5 ShardingSphere-Proxy功能擴展

  • ShardingSphere-Proxy 支持通過 SPI(Service Provider Interface)機制 進行自定義擴展,只要將自定義的擴展功能(如自定義算法、策略等)按照 SPI 規范打成 Jar 包,放入 ShardingSphere-Proxy 的 lib 目錄,就能被 ShardingSphere-Proxy 加載并使用;

  • 自定義主鍵生成器為例:

    • 實現 KeyGeneratorAlgorithm 接口,用于生成自定義格式的主鍵;
    • 生成主鍵時,結合當前時間戳(格式化為 yyyyMMddHHmmssSSS)和自增原子變量,保證主鍵的唯一性和有序性;
    public class MyKeyGeneratorAlgorithm implements KeyGeneratorAlgorithm {private AtomicLong atom = new AtomicLong(0);private Properties props;@Overridepublic Comparable<?> generateKey() {LocalDateTime ldt = LocalDateTime.now();// 格式化時間為 “年月日時分秒毫秒” 格式String timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(ldt);// 結合自增數生成主鍵(時間戳 + 自增數)return Long.parseLong(timestamp + atom.incrementAndGet());}@Overridepublic Properties getProps() {return this.props;}@Overridepublic String getType() {// 自定義算法的類型標識,配置時會用到return "MYKEY";}@Overridepublic void init(Properties props) {this.props = props;}
    }
    
  • 要將自定義類和對應的 SPI 文件打成 Jar 包,需在 pom.xml 中配置 maven-jar-plugin

    • 指定要打包的自定義類(com/your/package/algorithm/**)和 SPI 配置文件(META-INF/services/*),生成包含擴展功能的 Jar 包;
    <build><plugins><!-- 將 SPI 擴展功能單獨打成 Jar 包 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.2.0</version><executions><execution><id>shardingJDBDemo</id><phase>package</phase><goals><goal>jar</goal></goals><configuration><classifier>spi-extention</classifier><includes><!-- 包含自定義算法的包路徑 --><include>com/your/package/algorithm/**</include><!-- 包含 SPI 配置文件(META-INF/services/ 下的文件) --><include>META-INF/services/*</include></includes></configuration></execution></executions></plugin></plugins>
    </build>
    
  • 將打包好的 Jar 包,放入 ShardingProxy 的 lib 目錄。之后在 ShardingProxy 的配置中,就可以像使用內置組件一樣,引用這個自定義的主鍵生成算法(如配置 keyGeneratorName: MYKEY)。

6 分庫分表數據遷移方案

  • 分庫分表場景下,數據遷移面臨兩大難題:

    • 海量數據遷移難度大:舊項目無分庫分表,或需調整分片規則時,數據量龐大,遷移工程浩大;

    • 業務無感知難度高:遷移過程中要保證業務正常運行,不能因遷移導致服務中斷;

  • 為平衡數據遷移業務連續性(在數據轉移的過程中,保證不影響業務正常進行),采用冷熱數據分離遷移

    • 冷數據

      • 即歷史存量數據(數據量大,無法一次性遷移);
      • 策略:通過定時任務逐步遷移,減少對業務的瞬間壓力;
    • 熱數據

      • 即業務實時產生的新數據;
      • 策略:保證雙寫(同時寫入舊庫和新庫),確保遷移過程中數據實時同步,業務不受影響;
  • 基于 ShardingSphere 的遷移方案

    在這里插入圖片描述

    • 熱數據雙寫(ShardingJDBC 數據雙寫庫)

      • 核心邏輯:用 ShardingSphereDataSource 替換舊的 DataSource,配置雙寫規則(核心業務表同時寫入舊庫和新庫);

      • 實現方式:在 ShardingJDBC 雙寫庫中,針對需遷移的核心表配置分片規則,通過定制分片算法實現一份數據寫兩份庫

    • 新庫分片寫入(ShardingJDBC 數據寫入庫)

      • 核心邏輯:針對新數據庫集群,配置專門的 ShardingJDBC 寫入庫,完整實現新的分片規則(即分庫分表的最終邏輯);

      • 關聯方式:將這個寫入庫配置到之前的雙寫庫中,保證新數據按新規則寫入新庫;

    • 冷數據增量遷移(定時任務 + ShardingProxy)

      • 冷數據特點:量大、遷移慢,需分批增量遷移;

      • 實現方式:

        • ElasticJob 等定時任務框架,分批讀取舊庫冷數據,按新分片規則寫入新庫;
        • 借助 ShardingProxy 服務,簡化新庫的分片邏輯(定時任務只需從舊庫讀、往新庫寫,分片規則由 ShardingProxy 統一管理);
        • 規則同步:通過 ShardingSphere Governance Center(如 Zookeeper),保證 ShardingProxy 和 ShardingJDBC 寫入庫的分片規則一致
    • 遷移完成后切換

      • 核心邏輯:冷數據遷移完成后,刪除雙寫庫和舊庫依賴,只保留 ShardingJDBC 寫入庫(新庫的分片邏輯);

      • 業務影響:應用層只需訪問一個 DataSource(底層由 ShardingSphere 切換為新庫邏輯),業務代碼幾乎無需修改;

  • 注意:遷移過程中,需梳理業務 SQL,確保 SQL 符合 ShardingSphere(尤其是 ShardingSphere-JDBC)的支持范圍,避免使用不兼容的 SQL 語法導致遷移或業務異常。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/922202.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/922202.shtml
英文地址,請注明出處:http://en.pswp.cn/news/922202.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mysql相關的面試題1

什么是聚集索引&#xff08;聚簇索引&#xff09;&#xff1f;什么是二級索引&#xff08;非聚簇索引&#xff09;&#xff1f; 聚集索引就是葉子節點關聯行數據的索引&#xff0c;二級索引就是葉子節點關聯主鍵的索引&#xff0c;聚集索引必須有且僅有一個&#xff0c;二級索引…

電涌保護器:為現代生活筑起一道隱形防雷網

何為電涌保護器&#xff1f;電涌保護器&#xff08;Surge Protective Device&#xff0c;簡稱SPD&#xff09;主要用于控制信號系統&#xff0c;保護電氣電子設備信號線路免受雷電電磁脈沖、感應過電壓、操作過電壓的影響&#xff0c;廣泛應用于工控、消防、安防監控、交通、電…

【uniapp微信小程序】掃普通鏈接二維碼打開小程序

需求&#xff1a;用戶A保存自己的邀請碼海報&#xff0c;用戶B掃描該普通連接二維碼&#xff0c;打開微信小程序&#xff0c;并且攜帶用戶A的邀請碼信息&#xff0c;用戶B登錄時&#xff0c;跟用戶A關聯&#xff0c;成為用戶A的下級。 tips&#xff1a;保存海報到手機相冊可以參…

LeetCode 378 - 有序矩陣中第 K 小的元素

文章目錄摘要描述題解答案題解代碼分析代碼解析示例測試及結果輸出結果時間復雜度空間復雜度總結摘要 在開發中&#xff0c;我們經常遇到需要處理大規模有序數據的場景&#xff0c;比如數據庫分頁、排行榜查詢、或者處理排序過的矩陣。LeetCode 第 378 題“有序矩陣中第 K 小的…

【Lua】Windows 下編寫 C 擴展模塊:VS 編譯與 Lua 調用全流程

? 目錄 ?&#x1f6eb; 導讀需求環境1?? 核心原理&#xff1a;Windows下Lua與C的交互邏輯2?? Windows下編寫步驟&#xff1a;以mymath模塊為例2.1 步驟1&#xff1a;準備Windows開發環境方式1&#xff1a;官網下載Lua源碼并編譯&#xff08;可控性高&#xff09;方式2&am…

Python快速入門專業版(二十九):函數返回值:多返回值、None與函數嵌套調用

目錄引一、多返回值&#xff1a;一次返回多個結果的優雅方式1. 多返回值的本質&#xff1a;隱式封裝為元組示例1&#xff1a;返回多個值的函數及接收方式2. 多返回值的接收技巧技巧1&#xff1a;用下劃線_忽略不需要的返回值技巧2&#xff1a;用*接收剩余值&#xff08;Python …

python使用pip安裝的包與卸載

1&#xff1a;基本卸載命令 # 卸載單個包 pip uninstall package_name# 示例&#xff1a;卸載requests包 pip uninstall requests2&#xff1a;卸載多個包 # 一次性卸載多個包 pip uninstall package1 package2 package3# 示例 pip uninstall requests numpy pandas3&#xff1…

超級流水線和標量流水線的原理

一、什么是流水線&#xff1f;要理解這兩個概念&#xff0c;首先要明白流水線&#xff08;Pipelining&#xff09; 的基本思想。想象一個汽車裝配工廠&#xff1a;* 沒有流水線&#xff1a;一個工人負責組裝一整輛汽車&#xff0c;裝完一輛再裝下一輛。效率很低。* 有了流水線&…

【Ansible】管理復雜的Play和Playbook知識點

1.什么是主機模式&#xff1f;答&#xff1a;主機模式是Ansible中用于從Inventory中篩選目標主機的規則&#xff0c;通過靈活的模式定義可精準定位需要執行任務的主機。2.主機模式的作用答&#xff1a;篩選目標&#xff1a;從主機清單中選擇一個或多個主機/組&#xff0c;作為P…

FastGPT源碼解析 Agent 智能體應用創建流程和代碼分析

FastGPT對話智能體創建流程和代碼分析 平臺作為agent平臺&#xff0c;平臺所有功能都是圍繞Agent創建和使用為核心的。平臺整合各種基礎能力&#xff0c;如大模型、知識庫、工作流、插件等模塊&#xff0c;通過可視化&#xff0c;在界面上創建智能體&#xff0c;使用全部基礎能…

缺失數據處理全指南:方法、案例與最佳實踐

如何處理缺失數據&#xff1a;方法、案例與最佳實踐 1. 引言 在數據分析和機器學習中&#xff0c;缺失數據是一個普遍存在的問題。如何處理缺失值&#xff0c;往往直接影響到后續分析和建模的效果。處理不當&#xff0c;不僅會浪費數據&#xff0c;還可能導致模型預測結果的不準…

為什么Cesium不使用vue或者react,而是 保留 Knockout

1. Knockout-ES5 插件的語法簡化優勢 自動深度監聽&#xff1a;Cesium 通過集成 Knockout-ES5 插件&#xff0c;允許開發者直接使用普通變量語法&#xff08;如 viewModel.property newValue&#xff09;替代繁瑣的 observable() 包裝&#xff0c;無需手動聲明每個可觀察屬性。…

Word怎么設置頁碼總頁數不包含封面和目錄頁

有時候使用頁碼格式是[第x頁/共x頁]或[x/x]時會遇到word總頁數和實際想要的頁數不一致&#xff0c;導致顯示不統一&#xff0c;這里介紹一個簡單的辦法&#xff0c;適用于比較簡單的情況。 一、wps版本 文章分節 首先將目錄頁與正文頁進行分節&#xff1a;在目錄頁后面選擇插入…

突破機器人通訊架構瓶頸,CAN/FD、高速485、EtherCAT,哪種總線才是最優解?

引言&#xff1a; 從協作機械臂到人形機器人&#xff0c;一文拆解主流總線技術選型困局 在機器人技術飛速發展的今天&#xff0c;從工廠流水線上的協作機械臂到科技展會上的人形機器人&#xff0c;它們的“神經系統”——通訊總線&#xff0c;正面臨著前所未有的挑戰。特斯拉O…

Java核心概念詳解:JVM、JRE、JDK、Java SE、Java EE (Jakarta EE)

1. Java是什么&#xff1f; Java首先是一種編程語言。它擁有特定的語法、關鍵字和結構&#xff0c;開發者可以用它來編寫指令&#xff0c;讓計算機執行任務。核心特點&#xff1a; Java最著名的特點是“一次編寫&#xff0c;到處運行”&#xff08;Write Once, Run Anywhere - …

OSPF高級技術 相關知識點

1.多區域OSPFospf 設計多區域原因&#xff1a;① 每個區域的路由器只需同步自己所在區域的鏈路狀態數據庫&#xff0c;分區域設 計可以使得每個區域的鏈路狀態數據庫得以減少。以降低路由器cpu、內存 的消耗。② 避免某區域內的網絡故障&#xff08;例如&#xff1a;接口頻繁up…

Linux / Windows 下連續發送多幀 8 字節指令,下位機只響應第一幀,第二幀“丟失”。

串口編程易錯點筆記 基于 serial::Serial&#xff08;wjwwood serial 庫&#xff09; 場景&#xff1a;Linux / Windows 下連續發送多幀 8 字節指令&#xff0c;下位機只響應第一幀&#xff0c;第二幀“丟失”。1. 現象 serial::Serial ser("/dev/ttyUSB0", 115200);…

三十九、案例-配置文件-參數配置化(了解即可,現在主流使用yml配置文件)

參數配置化-問題引出參數配置化-問題解決參數配置化-代碼與過程解析代碼&#xff1a; AliOSSUtils&#xff08;工具類&#xff09; package com.itheima.utils;import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import org.springframework.beans.factory.…

Linux之virtio實現原理--pci 基礎

一、概述 virtio設備可以基于不同總線來實現&#xff0c;本文介紹基于pci實現的virtio-pci設備。以virtio-blk為例&#xff0c;首先介紹PCI配置空間內容&#xff0c;virtio-pci實現的硬件基礎——capability&#xff0c;最后分析PIC設備的初始化以及virtio-pci設備的初始化。 …

Claude-Flow AI協同開發:從“CTO”到“人機共生體”的AI協同開發

6.1 思維的終極融合&#xff1a;從“CTO”到“人機共生體” (Human-AI Symbiote) 在之前的章節中&#xff0c;我們逐步將您的角色從“開發者”提升為“項目經理”&#xff0c;最終定位為整個“人機混合團隊的CTO”。這個模型強調的是一種 “指揮-控制” (Command-and-Control) …