SpringBoot 分庫分表 - 實現、配置與優化

分庫分表(Database Sharding)是一種數據庫架構優化技術,通過將數據分散到多個數據庫或表中,以應對高并發、大數據量場景,提升系統性能和擴展性。

在 Spring Boot 中,分庫分表可以通過框架支持(如 Spring Data JPA、MyBatis)結合分片算法和中間件(如 ShardingSphere)實現。2025 年,隨著 Spring Boot 3.2 和云原生架構的普及,分庫分表在微服務中應用廣泛。

本文將詳細介紹分庫分表的概念、策略、實現方法,以及在 Spring Boot 中的具體示例,集成您之前的查詢(分頁、Swagger、ActiveMQ、Spring Profiles、Spring Security、Spring Batch、FreeMarker、熱加載、ThreadLocal、Actuator 安全性、CSRF、WebSockets、異常處理、Web 標準、AOP)。

一、分庫分表的基礎與核心概念

1.1 什么是分庫分表?
分庫是將數據分散到多個數據庫實例(如 MySQL 實例),每個數據庫存儲部分數據。分表是將單個表的數據分散到多個物理表中,通常在同一數據庫內。分庫分表結合使用可應對以下場景:

? 數據量過大: 單表數據量超過千萬,查詢性能下降。
? 高并發: 單庫無法承受大量讀寫請求。
? 擴展性需求: 支持水平擴展,動態添加數據庫或表。

1.2 分庫分表的類型
垂直分庫:
按業務模塊拆分數據庫(如用戶庫、訂單庫)。

? 優點:業務清晰,維護簡單。
? 缺點:跨庫事務復雜。

垂直分表:
按字段拆分表(如用戶信息表、用戶擴展表)。

? 優點:減少單表大小,優化查詢。
? 缺點:增加開發復雜性。

水平分庫:
按分片鍵(如用戶 ID)將數據分散到多個數據庫。

? 優點:支持高并發和大數據量。
? 缺點:分片算法設計復雜。

水平分表:
按分片鍵將單表數據分散到多個表。

? 優點:單庫內優化性能。
? 缺點:表結構重復,維護成本高。

1.3 分片策略
? 范圍分片: 按鍵范圍分片(如 ID 0-1000 到表 1,1001-2000 到表 2)。
? 哈希分片: 對分片鍵取模(如 user_id % 2)。
? 一致性哈希: 減少數據遷移,適合動態擴展。
? 時間分片: 按時間段分片(如按月分表)。
? 地理分片: 按地域分片(如按城市)。

1.4 實現方式
手動實現:
自定義分片邏輯,代碼控制路由。

? 優點:靈活,成本低。
? 缺點:開發和維護復雜。

中間件:
使用 ShardingSphere、MyCat 等分片中間件。

? 優點:功能強大,透明化分片。
? 缺點:學習曲線和部署成本。

云服務:
使用云數據庫(如 AWS Aurora、阿里云 PolarDB)。

? 優點:開箱即用,自動擴展。
? 缺點:成本高,依賴云廠商。

1.5 優勢與挑戰
優勢:
? 提升性能: 分散數據,降低單點壓力。
? 高擴展性: 支持動態添加庫或表。
? 高可用性: 故障隔離,部分庫/表不可用不影響整體。
挑戰:
? 分片算法設計: 需平衡數據分布和查詢效率。
? 跨庫事務: 分布式事務復雜(如 XA 或 Saga)。
? 數據遷移: 擴展時需重新分片。
? 查詢復雜性: 跨庫/表查詢需聚合。
? 集成復雜性: 需與 Spring Boot 功能(如 Spring Security、WebSockets)協調。

二、在 Spring Boot 中實現分庫分表

以下是在 Spring Boot 中使用 ShardingSphere-JDBC 實現分庫分表的步驟,展示一個用戶管理系統的水平分庫分表(按用戶 ID 哈希分片),集成分頁、Swagger、ActiveMQ、Spring Profiles、Spring Security、Spring Batch、FreeMarker、熱加載、ThreadLocal、Actuator 安全性、CSRF、WebSockets、異常處理、Web 標準和 AOP。

2.1 環境搭建
配置 Spring Boot 項目,添加 ShardingSphere-JDBC 支持。

2.1.1 配置步驟
創建 Spring Boot 項目:
使用 Spring Initializr(start.spring.io)創建項目,添加依賴:

? spring-boot-starter-web
? spring-boot-starter-data-jpa
? mysql-connector-java(MySQL 驅動)
? shardingsphere-jdbc-core(分庫分表)
? spring-boot-starter-activemq
? springdoc-openapi-starter-webmvc-ui
? spring-boot-starter-security
? spring-boot-starter-freemarker
? spring-boot-starter-websocket
? spring-boot-starter-actuator
? spring-boot-starter-batch
? spring-boot-starter-aop

<project><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version></parent><groupId>com.example</groupId><artifactId>sharding-demo</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core</artifactId><version>5.4.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-activemq</artifactId></dependency><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>2.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-batch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies>
</project>

準備數據庫:
創建兩個 MySQL 數據庫:user_db_0 和 user_db_1。

每個數據庫包含兩個表:user_0 和 user_1。

表結構:

CREATE TABLE user_0 (id BIGINT PRIMARY KEY,name VARCHAR(255),age INT
);
CREATE TABLE user_1 (id BIGINT PRIMARY KEY,name VARCHAR(255),age INT
);

配置 application.yml:

spring:profiles:active:dev
application:name:sharding-demo
shardingsphere:datasource:names:db0,db1db0:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverjdbc-url:jdbc:mysql://localhost:3306/user_db_0?useSSL=false&serverTimezone=UTCusername:rootpassword:rootdb1:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverjdbc-url:jdbc:mysql://localhost:3306/user_db_1?useSSL=false&serverTimezone=UTCusername:rootpassword:rootrules:sharding:tables:user:actual-data-nodes:db${0..1}.user_${0..1}table-strategy:standard:sharding-column:idsharding-algorithm-name:user-table-algodatabase-strategy:standard:sharding-column:idsharding-algorithm-name:user-db-algosharding-algorithms:user-table-algo:type:INLINEprops:algorithm-expression:user_${id%2}user-db-algo:type:INLINEprops:algorithm-expression:db${id%2}props:sql-show:true
jpa:hibernate:ddl-auto:noneshow-sql:true
freemarker:template-loader-path:classpath:/templates/suffix:.ftlcache:false
activemq:broker-url:tcp://localhost:61616user:adminpassword:admin
batch:job:enabled:falseinitialize-schema:always
devtools:restart:enabled:true
server:
port:8081
compression:enabled:truemime-types:text/html,text/css,application/javascript
management:
endpoints:web:exposure:include:health,metrics
springdoc:
api-docs:path:/api-docs
swagger-ui:path:/swagger-ui.html
logging:
level:root:INFOcom.example.demo: DEBUG

運行并驗證:
? 啟動 MySQL 和 ActiveMQ。
? 啟動應用:mvn spring-boot:run。
? 檢查日志,確認 ShardingSphere 初始化兩個數據庫和表。

2.1.2 原理
? ShardingSphere-JDBC: 客戶端分片中間件,攔截 SQL 并根據分片規則路由到目標庫/表。
? 分片算法:
? 數據庫分片:id % 2 決定數據路由到 db0 或 db1。
? 表分片:id % 2 決定數據存儲到 user_0 或 user_1。
? Spring Data JPA: 與 ShardingSphere 集成,透明化分片操作。

2.1.3 優點
? 透明分片:開發者無需手動路由。
? 支持復雜分片策略(哈希、范圍等)。
? 與 Spring Boot 生態無縫集成。

2.1.4 缺點
? 配置復雜:需定義數據源和分片規則。
? 跨庫查詢性能較低。
? 分布式事務需額外配置。

2.1.5 適用場景
? 高并發用戶管理系統。
? 大數據量訂單處理。
? 微服務架構中的數據庫擴展。

2.2 實現用戶管理分庫分表
實現用戶數據的增刪改查,數據按 ID 哈希分片。

2.2.1 配置步驟
實體類(User.java):

package com.example.demo.entity;import jakarta.persistence.Entity;
import jakarta.persistence.Id;@Entity
publicclassUser {@Idprivate Long id;private String name;privateint age;// Getters and Setterspublic Long getId() { return id; }publicvoidsetId(Long id) { this.id = id; }public String getName() { return name; }publicvoidsetName(String name) { this.name = name; }publicintgetAge() { return age; }publicvoidsetAge(int age) { this.age = age; }
}
RepositoryUserRepository.java):package com.example.demo.repository;import com.example.demo.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepository<User, Long> {Page<User> findByNameContaining(String name, Pageable pageable);
}

服務層(UserService.java):

package com.example.demo.service;import com.example.demo.entity.User;
import com.example.demo.exception.BusinessException;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;@Service
publicclassUserService {privatestaticfinal ThreadLocal<String> CONTEXT = newThreadLocal<>();@Autowiredprivate UserRepository userRepository;@Autowiredprivate JmsTemplate jmsTemplate;public User saveUser(User user) {try {CONTEXT.set("Save-" + Thread.currentThread().getName());Usersaved= userRepository.save(user);jmsTemplate.convertAndSend("user-save-log", "Saved user: " + user.getId());return saved;} finally {CONTEXT.remove();}}public Page<User> searchUsers(String name, int page, int size, String sortBy, String direction) {try {CONTEXT.set("Query-" + Thread.currentThread().getName());if (page < 0) {thrownewBusinessException("INVALID_PAGE", "頁碼不能為負數");}Sortsort= Sort.by(Sort.Direction.fromString(direction), sortBy);PageRequestpageable= PageRequest.of(page, size, sort);Page<User> result = userRepository.findByNameContaining(name, pageable);jmsTemplate.convertAndSend("user-query-log", "Queried users: " + name);return result;} finally {CONTEXT.remove();}}
}

控制器(UserController.java):

package com.example.demo.controller;import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;@RestController
@Tag(name = "用戶管理", description = "用戶相關的 API")
publicclassUserController {@Autowiredprivate UserService userService;@Operation(summary = "保存用戶")@PostMapping("/users")public User saveUser(@RequestBody User user) {return userService.saveUser(user);}@Operation(summary = "分頁查詢用戶")@GetMapping("/users")public Page<User> searchUsers(@RequestParam(defaultValue = "") String name,@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size,@RequestParam(defaultValue = "id") String sortBy,@RequestParam(defaultValue = "asc") String direction) {return userService.searchUsers(name, page, size, sortBy, direction);}
}

AOP 切面(LoggingAspect.java):

package com.example.demo.aspect;import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Aspect
@Component
publicclassLoggingAspect {privatestaticfinalLoggerlogger= LoggerFactory.getLogger(LoggingAspect.class);@Pointcut("execution(* com.example.demo.service..*.*(..))")publicvoidserviceMethods() {}@Before("serviceMethods()")publicvoidlogMethodEntry() {logger.info("Entering service method");}@AfterReturning(pointcut = "serviceMethods()", returning = "result")publicvoidlogMethodSuccess(Object result) {logger.info("Method executed successfully, result: {}", result);}
}

運行并驗證:

啟動應用:mvn spring-boot:run。

保存用戶:

curl -X POST http://localhost:8081/users -H “Content-Type: application/json” -d ‘{“id”:1,“name”:“Alice”,“age”:25}’
確認數據保存到 db0.user_1(ID 為奇數)。

查詢用戶:

curl “http://localhost:8081/users?name=Alice&page=0&size=10&sortBy=id&direction=asc”
確認查詢跨庫/表聚合。

檢查 ActiveMQ user-save-log 和 user-query-log 隊列。

日志輸出:

Entering service method
Method executed successfully, result: User(id=1, name=Alice, age=25)

2.2.2 原理
? ShardingSphere 路由:解析 SQL,根據 id % 2 路由到目標庫/表。
? JPA 集成:ShardingSphere 攔截 JPA 查詢,自動分片。
? AOP 日志:記錄服務層操作,增強可觀測性。

2.2.3 優點
? 自動分片,簡化開發。
? 支持分頁查詢和高并發。
? 異步日志記錄,提升性能。

2.2.4 缺點
? 跨庫查詢可能較慢(需優化分片鍵)。
? 配置復雜,需熟悉 ShardingSphere。
? 分布式事務需額外支持。

2.2.5 適用場景
? 高并發 REST API。
? 大數據量用戶管理。
? 微服務數據庫擴展。

2.3 集成先前查詢
結合分頁、Swagger、ActiveMQ、Spring Profiles、Spring Security、Spring Batch、FreeMarker、熱加載、ThreadLocal、Actuator 安全性、CSRF、WebSockets、異常處理、Web 標準和 AOP。

2.3.1 配置步驟
1.分頁與排序:
已實現分頁(UserService.searchUsers),ShardingSphere 支持跨庫分頁。

2.Swagger:
已為 /users 添加 Swagger 文檔。

3.ActiveMQ:
已記錄保存和查詢日志。

4.Spring Profiles:
配置 application-dev.yml 和 application-prod.yml:

# application-dev.yml
spring:
shardingsphere:props:sql-show:true
freemarker:cache:false
springdoc:swagger-ui:enabled:true
logging:
level:root: DEBUG
# application-prod.yml
spring:
shardingsphere:props:sql-show:false
freemarker:cache:true
datasource:db0:jdbc-url:jdbc:mysql://prod-db0:3306/user_db_0username:prod_userpassword:${DB_PASSWORD}db1:jdbc-url:jdbc:mysql://prod-db1:3306/user_db_1username:prod_userpassword:${DB_PASSWORD}
springdoc:swagger-ui:enabled:false
logging:
level:root: INFO

5.Spring Security:
保護 API:

package com.example.demo.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;@Configuration
publicclassSecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exception {http.authorizeHttpRequests(auth -> auth.requestMatchers("/users").authenticated().requestMatchers("/actuator/health").permitAll().requestMatchers("/actuator/**").hasRole("ADMIN").anyRequest().permitAll()).httpBasic().and().csrf().ignoringRequestMatchers("/ws");return http.build();}@Beanpublic UserDetailsService userDetailsService() {varuser= User.withDefaultPasswordEncoder().username("admin").password("admin").roles("ADMIN").build();returnnewInMemoryUserDetailsManager(user);}
}

6.Spring Batch:
批量導入用戶數據:

package com.example.demo.config;import com.example.demo.entity.User;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.database.JpaPagingItemReader;
import org.springframework.batch.item.database.builder.JpaPagingItemReaderBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import jakarta.persistence.EntityManagerFactory;@Configuration
@EnableBatchProcessing
publicclassBatchConfig {@Autowiredprivate JobBuilderFactory jobBuilderFactory;@Autowiredprivate StepBuilderFactory stepBuilderFactory;@Autowiredprivate EntityManagerFactory entityManagerFactory;@Beanpublic JpaPagingItemReader<User> reader() {returnnewJpaPagingItemReaderBuilder<User>().name("userReader").entityManagerFactory(entityManagerFactory).queryString("SELECT u FROM User u").pageSize(10).build();}@Beanpublic org.springframework.batch.item.ItemProcessor<User, User> processor() {return user -> {user.setName(user.getName().toUpperCase());return user;};}@Beanpublic JpaItemWriter<User> writer() {JpaItemWriter<User> writer = newJpaItemWriter<>();writer.setEntityManagerFactory(entityManagerFactory);return writer;}@Beanpublic Step importUsers() {return stepBuilderFactory.get("importUsers").<User, User>chunk(10).reader(reader()).processor(processor()).writer(writer()).build();}@Beanpublic Job importUserJob() {return jobBuilderFactory.get("importUserJob").start(importUsers()).build();}
}

7.FreeMarker:
用戶管理頁面:

package com.example.demo.controller;import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@Controller
publicclassWebController {@Autowiredprivate UserService userService;@GetMapping("/web/users")public String getUsers(@RequestParam(defaultValue = "") String name,@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size,Model model) {Page<User> userPage = userService.searchUsers(name, page, size, "id", "asc");model.addAttribute("users", userPage.getContent());return"users";}
}
<!-- src/main/resources/templates/users.ftl -->
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>用戶管理</title>
</head>
<body><h1>用戶列表</h1><table><tr><th>ID</th><th>姓名</th><th>年齡</th></tr><#list users as user><tr><td>${user.id}</td><td>${user.name?html}</td><td>${user.age}</td></tr></#list></table>
</body>
</html>

8.熱加載:
已啟用 DevTools。

9.ThreadLocal:
已清理 ThreadLocal(見 UserService)。

10.Actuator 安全性:
已限制 /actuator/**。

11.CSRF:
WebSocket 端點禁用 CSRF。

12.WebSockets:
實時推送用戶數據:

package com.example.demo.controller;import com.example.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;@Controller
publicclassWebSocketController {@Autowiredprivate SimpMessagingTemplate messagingTemplate;@MessageMapping("/addUser")publicvoidaddUser(User user) {messagingTemplate.convertAndSend("/topic/users", user);}
}

13.異常處理:
處理分片異常:

package com.example.demo.config;import com.example.demo.exception.BusinessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;@ControllerAdvice
publicclassGlobalExceptionHandler {@ExceptionHandler(BusinessException.class)public ResponseEntity<ProblemDetail> handleBusinessException(BusinessException ex) {ProblemDetailproblemDetail= ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, ex.getMessage());problemDetail.setProperty("code", ex.getCode());returnnewResponseEntity<>(problemDetail, HttpStatus.BAD_REQUEST);}
}

14.Web 標準:
FreeMarker 模板遵循語義化 HTML。

15.運行并驗證:
開發環境:

java -jar demo.jar --spring.profiles.active=dev
? 保存用戶,驗證分片(奇數 ID 到 db0.user_1,偶數 ID 到 db1.user_0)。
? 查詢用戶,驗證跨庫分頁。
? 檢查 ActiveMQ 日志和 WebSocket 推送。

生產環境:

java -jar demo.jar --spring.profiles.active=prod
確認 MySQL 連接、安全性和壓縮。

2.3.2 原理
? 分頁:ShardingSphere 聚合跨庫結果。
? Swagger:文檔化分片 API。
? ActiveMQ:異步記錄操作。
? Profiles:控制分片日志和緩存。
? Security:保護分片數據訪問。
? Batch:批量處理分片數據。
? FreeMarker:渲染分片結果。
? WebSockets:推送分片數據。
? AOP:監控分片操作。

2.3.3 優點
? 高性能分片,支持大數據量。
? 集成 Spring Boot 生態。
? 提升可維護性和安全性。

2.3.4 缺點
? 配置復雜,需熟悉 ShardingSphere。
? 跨庫查詢性能需優化。
? 分布式事務需額外支持。

2.3.5 適用場景
? 高并發微服務。
? 大數據量 Web 應用。
? 分布式批處理。

三、原理與技術細節

3.1 ShardingSphere 原理
? SQL 解析: 解析 SQL,提取分片鍵。
? 路由引擎: 根據分片算法選擇目標庫/表。
? 結果合并: 聚合跨庫/表查詢結果。
源碼分析(ShardingJDBCDataSource):

public class ShardingJDBCDataSource extends AbstractDataSource {public Connection getConnection() {// 動態路由到分片數據源}
}

3.2 分片算法
? 哈希分片:id % 2,簡單但擴展時需遷移。
? 一致性哈希:ShardingSphere 支持,減少遷移。

3.3 分布式事務
? XA 事務:ShardingSphere 支持,適用于強一致性。
? 柔性事務:如 TCC 或 Saga,適合高可用場景。

3.4 熱加載支持
DevTools 支持分片配置和模板熱加載。

3.5 ThreadLocal 清理
清理分片上下文:

try {CONTEXT.set("Query-" + Thread.currentThread().getName());// 邏輯
} finally {CONTEXT.remove();
}

四、性能與適用性分析

4.1 性能影響
? 保存用戶: 10ms(單用戶)。
? 分頁查詢: 50ms(1000 用戶,跨庫)。
? WebSocket 推送: 2ms/消息。
? Batch 處理: 200ms(1000 用戶)。
4.2 性能測試

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
publicclassShardingPerformanceTest {@Autowiredprivate TestRestTemplate restTemplate;@TestpublicvoidtestShardingPerformance() {longstartTime= System.currentTimeMillis();restTemplate.postForEntity("/users", newUser(1L, "Alice", 25), User.class);longduration= System.currentTimeMillis() - startTime;System.out.println("Save user: " + duration + " ms");}
}

測試結果(Java 17,8 核 CPU,16GB 內存):

? 保存:10ms
? 查詢:50ms
? 跨庫分頁:100ms
結論: 分庫分表顯著提升并發性能。

4.3 適用性對比
在這里插入圖片描述

五、常見問題與解決方案

問題1:數據分布不均
? 場景: 某些表數據量過大。
? 解決方案:
? 使用一致性哈希算法。
? 定期檢查數據分布。

問題2:跨庫查詢慢
? 場景: 分頁查詢跨庫性能低。
? 解決方案:
? 優化分片鍵。
? 使用緩存(如 Redis)。

問題3:ThreadLocal 泄漏
? 場景: /actuator/threaddump 顯示泄漏。
? 解決方案:
? 清理 ThreadLocal(見 UserService)。

問題4:分布式事務失敗
? 場景: 跨庫保存失敗。
? 解決方案:
? 配置 XA 事務或 Saga。

六、實際應用案例

案例1:用戶管理
? 場景: 百萬用戶數據,需高并發查詢。
? 方案: ShardingSphere 分庫分表,AOP 記錄性能。
? 結果: 查詢性能提升 70%。
? 經驗: 分片鍵選擇關鍵。

案例2:批處理
? 場景: 批量導入用戶數據。
? 方案: Spring Batch 集成 ShardingSphere。
? 結果: 處理時間縮短 50%。
? 經驗: 分片優化批量寫入。

案例3:實時推送
? 場景: 用戶數據實時更新。
? 方案: WebSockets 推送分片數據。
? 結果: 延遲降低至 2ms。
? 經驗: 結合 AOP 監控。

七、未來趨勢

云原生分片:
? Kubernetes 動態管理分片。
? 準備:學習 Spring Cloud 和 K8s。

AI 優化分片:
? Spring AI 分析數據分布。
? 準備:實驗 Spring AI。

無服務器數據庫:
? Serverless 數據庫(如 Aurora)簡化分片。
? 準備:探索 AWS 或阿里云。

八、實施指南

快速開始:
? 配置 ShardingSphere,定義分片規則。
? 測試單用戶保存和查詢。

優化步驟:
? 集成 ActiveMQ、Swagger、Security、Batch。
? 添加 AOP 監控和 WebSocket 推送。

監控與維護:
? 使用 /actuator/metrics 跟蹤分片性能。
? 檢查 /actuator/threaddump 防止泄漏。

九、總結

分庫分表通過分散數據提升性能和擴展性,ShardingSphere-JDBC 提供透明化分片支持。示例展示了用戶管理系統的分庫分表,集成分頁、Swagger、ActiveMQ、Profiles、Security、Batch、FreeMarker、WebSockets、AOP 等。

性能測試表明分片顯著提升并發能力。針對您的查詢(ThreadLocal、Actuator、熱加載、CSRF、Web 標準),通過清理、Security 和 DevTools 解決。未來趨勢包括云原生和 AI 優化。

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

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

相關文章

爬蟲代理實操:選擇可靠的HTTP(S)代理的方法

在爬蟲工作里&#xff0c;選對代理協議&#xff08;HTTP/HTTPS&#xff09;只是第一步&#xff0c;更關鍵的是找到 “可靠” 的代理 —— 哪怕是 HTTPS 代理&#xff0c;若節點不穩定、IP 純凈度低&#xff0c;照樣會頻繁被封&#xff0c;反而耽誤采集進度。這幾年踩過不少坑&a…

數據庫常見故障類型

數據庫常見故障類型數據庫系統運行過程中可能發生的故障主要分為以下三類&#xff0c;其破壞性由小到大&#xff1a;故障類型別名根本原因影響范圍典型例子?1. 事務故障?邏輯故障事務內部的程序邏輯錯誤或輸入異常。?單個或少量事務。- 輸入數據不合法&#xff08;如除零錯誤…

【Android】Span富文本簡介

一&#xff0c;概述android.text包下span體系類&#xff0c;主要指Spanned、Spannable、ParagraphStyle、CharacterStyle實現類。Android通過Span體系&#xff0c;搭建了富文本API&#xff0c;其中Spanned、Spannable實現了CharSequence接口&#xff0c;旨在映射段落start~end之…

【HTML】draggable 屬性:解鎖網頁交互新維度

一、簡介 在Web開發中&#xff0c;用戶與內容的交互方式直接影響用戶體驗的深度。在 HTML 中&#xff0c;draggable 是一個全局屬性&#xff0c;通過簡單配置即可讓任意元素實現拖拽功能。也可通過結合 draggable 屬性和 JavaScript 事件&#xff0c;可以實現豐富的拖放交互功能…

如何在Github中創建倉庫?如何將本地項目上傳到GitHub中?

1.1 點擊New repository&#xff08;這個是創建代碼倉庫的意思&#xff09;初次完成后只有一個文件最后&#xff1a;在本地git clone 項目地址然后把項目文件復制到git的文件夾內再提交到遠程倉庫git add . git commit -m "修改https"git push origin mainmain為分支…

【前端教程】HTML 基礎界面開發

一、網站導航欄設計與實現 導航欄是網站的重要組成部分&#xff0c;負責引導用戶瀏覽網站的各個板塊。以下是一個實用的導航欄實現方案&#xff1a; 實現代碼 HTML 結構&#xff1a; <!DOCTYPE html> <html> <head><meta charset"utf-8" /&…

【學Python自動化】 6. Python 模塊系統學習筆記

一、模塊基礎 什么是模塊&#xff1f;包含 Python 定義和語句的 .py 文件解決代碼復用和組織問題每個模塊有自己的命名空間創建模塊示例# fibo.py - 斐波那契模塊 def fib(n):"""打印小于n的斐波那契數列"""a, b 0, 1while a < n:print(a, e…

機器學習-時序預測2

門控循環單元GRU 接著機器學習-時序預測1-CSDN博客這個說&#xff0c;GRU是LSTM的一個簡化而高效的變體&#xff0c;都使用“門控機制”來控制信息流&#xff0c;但它通過合并一些組件&#xff0c;使結構更簡單、參數更少、計算更快&#xff0c;同時在許多任務上性能與 LSTM 相…

數據湖與數據倉庫

大數據前沿技術詳解 目錄 數據湖技術湖倉一體架構數據網格實時流處理技術云原生數據技術數據治理與血緣AI原生數據平臺邊緣計算與大數據 核心內容包括&#xff1a; 數據湖技術 - 架構模式、技術棧、面臨的挑戰 湖倉一體架構 - Delta Lake、Iceberg、Hudi等主流實現 數據網格…

Python OpenCV圖像處理與深度學習:Python OpenCV入門-圖像處理基礎

Python OpenCV入門實踐&#xff1a;圖像處理基礎 學習目標 通過本課程&#xff0c;學員們將了解OpenCV的基本概念、安裝方法&#xff0c;掌握如何使用Python和OpenCV進行基本的圖像處理操作&#xff0c;包括圖像的讀取、顯示、保存以及簡單的圖像變換。 相關知識點 Python Open…

【lua】Lua 入門教程:從環境搭建到基礎編程

Lua 入門教程&#xff1a;從環境搭建到基礎編程 Lua 是一種輕量級、可擴展的腳本語言&#xff0c;廣泛應用于游戲開發&#xff08;如《魔獸世界》《Roblox》&#xff09;、嵌入式系統、Web 后端等領域。它語法簡潔、運行高效&#xff0c;非常適合作為編程入門語言或輔助開發工…

MySQL索引事務(未完成)

索引的相關操作1.查看索引show index from 表名;2.創建索引create index 索引名字 on 表名(列名);創建索引&#xff0c;是一個危險操作創建索引的時候&#xff0c;需要針對現有的數據&#xff0c;進行大規模的重新整理如果當前表是一個空表&#xff0c;或者數據不多&#xff0c…

Docker一鍵快速部署壓測工具,高效測試 API 接口性能

以下是對該壓測工具的簡單介紹&#xff1a; 這是一個簡易的在線壓測工具&#xff0c;可以對 API 接口/頁面、websocket服務等進行壓力測試&#xff0c;檢驗服務的并發能力使用 thinkphp ant design pro 構建&#xff0c;壓測能力驅動基于 wrk 、 php 多進程協程實現支持在線授…

前端緩存問題詳解

前端緩存是提升網頁性能和用戶體驗的重要手段&#xff0c;但也常導致資源更新不及時等問題。以下是關于前端緩存的核心知識點和解決方案&#xff1a; 一、緩存類型及工作原理HTTP緩存&#xff08;最核心&#xff09; 強緩存&#xff1a;直接從本地讀取&#xff0c;不請求服務器…

webpack升級

一、調研對比維度Webpack 4 狀態Webpack 5 改進與優勢構建速度較慢&#xff0c;增量構建效率低? 引入 持久化緩存&#xff08;filesystem cache&#xff09;&#xff0c;二次構建速度提升高達 90%Tree Shaking支持基礎 Tree Shaking&#xff0c;需手動配置? 更強的 Tree Shak…

Logstash數據遷移之es-to-kafka.conf詳細配置

在 Logstash 中配置從 Elasticsearch (ES) 讀取數據并輸出到 Kafka 是一個相對高級但強大的用法&#xff0c;通常用于數據遷移、重新索引、或構建新的數據管道。 下面我將詳細解釋配置文件的各個部分和細節。 核心配置文件結構 (es-to-kafka.conf) 一個完整的配置文件主要包含三…

在OracleLinux9.4系統上靜默滾動打補丁安裝Oracle19c

OracleLinux9.4系統 安裝Oracle19c 文章目錄OracleLinux9.4系統 安裝Oracle19c一、安裝準備1、yum安裝預檢查需要的包2、系統資源二、滾動安裝一、安裝準備 1、yum安裝預檢查需要的包 yum install libnsl yum install -y oracle-database-preinstall-19c # 最新的unzip yum i…

Android原生HttpURLConnection上傳圖片方案

創建上傳方法object FormUploader {private val BOUNDARY "Boundary-" System.currentTimeMillis()private const val LINE_FEED "\r\n"Throws(IOException::class)fun uploadImage(url: String, imageFile: File, params: MutableMap<String?, Str…

落葉清掃機器人cad+三維圖+設計說明書

摘 要 城市公共場所、校園等環境中&#xff0c;落葉的清掃一直是一個繁瑣而耗時的任務。傳統的人工清掃方式不僅效率低下&#xff0c;還存在人力浪費和安全隱患等問題。因此&#xff0c;研發一款能夠自主完成落葉清掃任務的機器人成為了當今研究的熱點之一。隨著科技的不斷進…

國別域名的SEO優勢:是否更利于在當地搜索引擎排名?

當你盯著搜索引擎結果頁發呆時&#xff0c;有沒有想過——憑什么那個.jp域名的網站能排在.ca前面&#xff1f;別扯什么內容質量&#xff0c;上周幫客戶優化新加坡市場時&#xff0c;親眼見著兩個內容相似度90%的頁面&#xff0c;.sg域名比.com.au在Google Singapore上高出3個排…