前言
在Java后端开发中,位置数据、日志数据等大流量数据,常需要与主业务数据分库存储,同时按时间分表(如按月分表)降低单表压力。本文基于JDK17+Druid1.2.27+SpringBoot3+MyBatis-Plus+ShardingSphere5技术栈,实现「主库MySQL(存业务数据)+ 从库PostgreSQL(存位置表+日志表,均按月分表)」的分库分表方案。
本文核心亮点:
-
✅ 配置极简规范:ShardingSphere独立配置,不与原生datasource冲突,可读性拉满
-
✅ 零业务字段侵入 :不依赖实体类中的
dbType字段,通过表级别配置明确路由规则 -
✅ 多表分表支持:同时实现Position位置表、Log日志表按月分表,规则独立互不干扰
-
✅ 双库适配:主库MySQL(业务)+ 从库PostgreSQL(大流量数据),自动路由
-
✅ 自动建表:定时任务每月自动创建下个月分表,使用模板表模式,SQL零重复
-
✅ 零配置类:无需手动编写DataSourceConfig,框架自动接管数据源
-
✅ 双库分页:MyBatis-Plus分页自动适配MySQL/PostgreSQL,支持动态方言识别
-
✅ 生产级监控:集成ShardingSphere执行引擎监控 + Prometheus指标暴露
一、技术栈版本确认(必看,避免版本冲突)
| 技术栈 | 版本 | 说明 |
|---|---|---|
| JDK | 17 | SpringBoot3最低要求,适配现代系统 |
| SpringBoot | 3.2.5 | 核心框架 |
| MyBatis-Plus | 3.5.6 | 简化CRUD,支持分页 |
| ShardingSphere | 5.5.0 | 分库分表核心 |
| Druid | 1.2.27 | 连接池(SpringBoot3专属) |
| MySQL | 8.0+ | 主库,存储主业务数据(如用户、订单) |
| PostgreSQL | 14+ | 从库,存储位置、日志等大流量分表数据 |
二、Maven依赖配置(完整无缺失)
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>sharding-multi-table-demo</artifactId>
<version>1.0.0</version>
<name>sharding-multi-table-demo</name>
<description>多表分库分表完整实践(Position+Log)</description>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- SpringBoot Web 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus 核心依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.6</version>
</dependency>
<!-- ShardingSphere JDBC 分库分表核心依赖 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.5.0</version>
</dependency>
<!-- Druid 连接池(SpringBoot3专属) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.27</version>
</dependency>
<!-- MySQL 8 驱动(主库使用) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- PostgreSQL 驱动(从库使用) -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Prometheus 监控(生产级) -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
三、核心配置文件(application.yml)- 生产优化版
XML
# ==============================================
# 项目名称:多表分库分表实践(Position+Log)
# 核心架构:主库MySQL(业务)+ 从库PostgreSQL(位置+日志)
# 分表规则:位置表、日志表均按月分表(表名格式:xxx_yyyyMM)
# 连接池:Druid1.2.27 | 框架:SpringBoot3 + MyBatis-Plus + ShardingSphere5
# 优化点:1.移除db_type字段依赖,表级别直接指定数据源
# 2.增加Prometheus监控配置
# 3.分页插件支持动态方言识别
# ==============================================
server:
port: 8080
servlet:
context-path: /sharding-demo
spring:
# 必须关闭!所有数据源交给ShardingSphere统一管理
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
# Actuator监控配置(生产级)
management:
endpoints:
web:
exposure:
include: health,info,prometheus,sharding
base-path: /actuator
metrics:
export:
prometheus:
enabled: true
tags:
application: sharding-demo
# ===================== ShardingSphere 分库分表核心配置 =====================
shardingsphere:
enabled: true
# 全局属性配置
props:
sql-show: false # 生产环境关闭SQL打印,减少日志开销
sql-simple: true
check-table-metadata-enabled: true # 开启表元数据检查
# 慢SQL阈值(毫秒),超过此值记录日志
sql-execution-timeout-milliseconds: 3000
# 多数据源配置
datasource:
names: master,slave
# 主库:MySQL
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/business_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8&allowPublicKeyRetrieval=true
username: root
password: ${MYSQL_PASSWORD:123456}
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
# 从库:PostgreSQL
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/position_db?useSSL=false&serverTimezone=Asia/Shanghai
username: postgres
password: ${POSTGRES_PASSWORD:123456}
druid:
initial-size: 8
min-idle: 8
max-active: 40
max-wait: 60000
validation-query: SELECT 1
test-while-idle: true
# ===================== 分片规则(优化版) =====================
rules:
sharding:
# 多表分表规则配置
tables:
# 位置表(明确指定从库,不依赖db_type字段)
position:
actual-data-nodes: slave.position_${202501..203012}
table-strategy:
standard:
sharding-column: create_time
sharding-algorithm-name: position-month
# 日志表(独立分表规则,可按天/月调整)
log:
actual-data-nodes: slave.log_${202501..203012}
table-strategy:
standard:
sharding-column: create_time
sharding-algorithm-name: log-month
# 默认数据库策略(不配置分库路由,避免全库扫描风险)
# 因为每个表在actual-data-nodes中已明确指定数据源,无需分库策略
default-database-strategy:
none: # 无分库策略,严格按照actual-data-nodes路由
# 分片算法定义
sharding-algorithms:
# 位置表按月分表算法
position-month:
type: MONTH
props:
datetime-pattern: yyyy-MM-dd HH:mm:ss
sharding-suffix-pattern: yyyyMM
# 日志表按月分表算法(可按需调整为按天:yyyyMMdd)
log-month:
type: MONTH
props:
datetime-pattern: yyyy-MM-dd HH:mm:ss
sharding-suffix-pattern: yyyyMM
# ===================== MyBatis-Plus 配置 =====================
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
call-setters-on-nulls: true
# 日志实现(生产环境可调整为Slf4jImpl)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: assign_id
# 逻辑删除(如不需要可注释)
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
# ===================== Druid 监控配置 =====================
druid:
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin
allow: 127.0.0.1
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,/actuator/*"
四、核心代码实现
4.1 包结构
TypeScript
com.example
├── ShardingMultiTableApplication.java # 启动类
├── config
│ ├── MybatisPlusConfig.java # MyBatis-Plus分页配置(双库适配)
│ └── ShardingMetricsConfig.java # ShardingSphere监控配置
├── entity
│ ├── Position.java # 位置表实体类(无db_type字段)
│ └── Log.java # 日志表实体类(无db_type字段)
├── mapper
│ ├── PositionMapper.java
│ └── LogMapper.java
├── service
│ ├── PositionService.java
│ └── LogService.java
└── schedule
└── TableCreateSchedule.java # 定时任务(模板表模式)
4.2 启动类
java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 开启定时任务
public class ShardingMultiTableApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingMultiTableApplication.class, args);
}
}
4.3 MyBatis-Plus分页配置(双库适配)
java
package com.example.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MyBatis-Plus配置 - 支持MySQL和PostgreSQL动态分页方言
*/
@Configuration
@MapperScan("com.example.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件:设置DbType为AUTO,自动识别数据库方言
// ShardingSphere会自动处理分库分表的分页合并
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
paginationInterceptor.setDbType(DbType.AUTO); // 自动识别MySQL/PostgreSQL
paginationInterceptor.setOverflow(false);
paginationInterceptor.setMaxLimit(1000L);
paginationInterceptor.setOptimizeJoin(true);
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
4.4 实体类
java
package com.example.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 位置表实体类
*/
@Data
@TableName("position") // 逻辑表名
public class Position {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long bizId; // 业务ID(如用户ID、订单ID)
private Double longitude; // 经度
private Double latitude; // 纬度
private String address; // 地址
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; // 分片键
private Integer locationType; // 位置类型
// 逻辑删除字段(表结构中需存在)
@TableLogic
private Integer deleted;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
}
java
package com.example.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 日志表实体类
*/
@Data
@TableName("log")
public class Log {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String content; // 日志内容
private Long operatorId; // 操作人ID
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; // 分片键
private String logLevel; // 日志级别
@TableLogic
private Integer deleted;
}
4.5 Mapper层
java
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.Position;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PositionMapper extends BaseMapper<Position> {
// 继承BaseMapper即可获得所有CRUD方法
}
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.Log;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LogMapper extends BaseMapper<Log> {
}
4.6 Service层(零分表逻辑)
java
package com.example.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Position;
import com.example.mapper.PositionMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class PositionService {
private final PositionMapper positionMapper;
/**
* 插入位置数据(自动路由到对应月表)
*/
public void savePosition(Position position) {
if (position.getCreateTime() == null) {
position.setCreateTime(LocalDateTime.now());
}
positionMapper.insert(position);
log.info("位置数据插入成功,ID: {}, 路由月份: {}",
position.getId(),
position.getCreateTime().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMM")));
}
/**
* 跨月查询(自动合并多表结果)
*/
public List<Position> queryByCrossMonth(Long bizId, LocalDateTime start, LocalDateTime end) {
LambdaQueryWrapper<Position> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Position::getBizId, bizId)
.between(Position::getCreateTime, start, end)
.orderByDesc(Position::getCreateTime);
return positionMapper.selectList(wrapper);
}
/**
* 分页查询(ShardingSphere自动合并多表分页)
*/
public Page<Position> pageQuery(Page<Position> page, LocalDateTime start, LocalDateTime end) {
LambdaQueryWrapper<Position> wrapper = new LambdaQueryWrapper<>();
wrapper.between(Position::getCreateTime, start, end)
.orderByDesc(Position::getCreateTime);
return positionMapper.selectPage(page, wrapper);
}
}
4.7 定时任务(模板表模式 + 动态建表)
java
package com.example.schedule;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* 定时任务:每月自动创建PostgreSQL分表
* 优化点:使用模板表模式,避免SQL重复维护
* 执行时间:每月最后一天 23:50:00
*/
@Slf4j
@Component
public class TableCreateSchedule {
@Resource
private JdbcTemplate jdbcTemplate;
// 模板表名称(预先创建好,包含所有字段和索引)
private static final String POSITION_TEMPLATE = "position_template";
private static final String LOG_TEMPLATE = "log_template";
/**
* 每月最后一天23:50执行
*/
@Scheduled(cron = "0 50 23 L * ?")
public void createNextMonthTables() {
String nextMonthSuffix = LocalDate.now().plusMonths(1)
.format(DateTimeFormatter.ofPattern("yyyyMM"));
log.info("开始创建下月分表,月份后缀: {}", nextMonthSuffix);
// 创建位置表分表
createTableFromTemplate(POSITION_TEMPLATE, "position", nextMonthSuffix);
// 创建日志表分表
createTableFromTemplate(LOG_TEMPLATE, "log", nextMonthSuffix);
log.info("✅ 下月分表创建完成!月份后缀: {}", nextMonthSuffix);
}
/**
* 从模板表创建新表(PostgreSQL语法)
* 优点:自动继承模板表的所有字段、索引、约束
*/
private void createTableFromTemplate(String templateName, String targetPrefix, String suffix) {
String targetTable = targetPrefix + "_" + suffix;
try {
// 检查表是否已存在
String checkSql = "SELECT to_regclass('" + targetTable + "')";
Object result = jdbcTemplate.queryForObject(checkSql, Object.class);
if (result != null) {
log.info("表 {} 已存在,跳过创建", targetTable);
return;
}
// 使用 LIKE 模板表创建新表(包含所有索引和约束)
String createSql = String.format(
"CREATE TABLE %s (LIKE %s INCLUDING ALL)",
targetTable, templateName
);
jdbcTemplate.execute(createSql);
log.info("✅ 分表创建成功: {} (基于模板表 {})", targetTable, templateName);
} catch (Exception e) {
log.error("创建分表失败: {}", targetTable, e);
// 可集成告警通知
}
}
/**
* 可选:提前创建下下个月的表(节假日容错)
*/
@Scheduled(cron = "0 0 10 28 * ?") // 每月28号10:00执行
public void preCreateNextNextMonthTables() {
LocalDate now = LocalDate.now();
// 如果是12月,提前创建2月的表;否则创建下下月
LocalDate target = now.plusMonths(2);
String suffix = target.format(DateTimeFormatter.ofPattern("yyyyMM"));
log.info("提前创建分表: {}", suffix);
createTableFromTemplate(POSITION_TEMPLATE, "position", suffix);
createTableFromTemplate(LOG_TEMPLATE, "log", suffix);
}
}
4.8 ShardingSphere监控配置(生产级)
java
package com.example.config;
import io.micrometer.core.instrument.MeterRegistry;
import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import javax.sql.DataSource;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* ShardingSphere 监控配置
* 暴露分片执行指标,用于Prometheus采集
*/
@Configuration
public class ShardingMetricsConfig {
@Resource
private DataSource dataSource;
@Resource
private MeterRegistry meterRegistry;
/**
* 自定义监控指标
*/
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "sharding-demo");
}
/**
* 定时采集ShardingSphere执行指标
* 监控:分片键命中率、跨表查询次数、慢SQL分布
*/
@PostConstruct
public void initShardingMetrics() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
// 每30秒采集一次执行指标
scheduler.scheduleAtFixedRate(() -> {
try {
if (dataSource instanceof ShardingSphereDataSourceFactory) {
// 获取执行引擎指标
// 注:ShardingSphere 5.x 支持通过SPI暴露Metrics,此处为简化示例
collectCustomMetrics();
}
} catch (Exception e) {
// 忽略采集异常
}
}, 10, 30, TimeUnit.SECONDS);
}
private void collectCustomMetrics() {
// 示例:记录JdbcTemplate执行次数
// 实际生产中可接入ShardingSphere官方Metrics扩展
meterRegistry.counter("sharding.query.total").increment();
}
}
五、生产环境优化建议
5.1 监控指标说明
| 指标 | 说明 | 告警阈值 |
|---|---|---|
sharding.cross_table_query_count |
跨表查询次数 | > 1000/分钟 |
sharding.miss_sharding_key_count |
未携带分片键的查询次数 | > 0 |
sharding.slow_query_count |
慢查询次数(>3秒) | > 10/分钟 |
sharding.table_count |
当前分表总数 | 监控变化趋势 |
5.2 常见问题排查
| 问题现象 | 排查方向 |
|---|---|
| 项目启动失败,提示数据源冲突 | 检查是否关闭了DataSourceAutoConfiguration |
| 插入数据报表不存在 | 1.检查定时任务是否开启;2.手动创建对应分表;3.确认模板表已创建 |
| 查询不到数据,但数据已插入 | 1.检查createTime格式是否与分片算法匹配;2.查看控制台SQL,确认路由表名正确 |
| PostgreSQL分页查询异常 | 确认MyBatis-Plus分页配置为DbType.AUTO |
| 慢查询增多 | 检查分表索引是否完整,或查询是否携带create_time范围 |
5.3 模板表初始化SQL
sql
-- 在PostgreSQL中预先创建模板表
-- position_template
CREATE TABLE position_template (
id BIGINT PRIMARY KEY,
biz_id BIGINT NOT NULL,
longitude NUMERIC(10,7),
latitude NUMERIC(10,7),
address VARCHAR(500),
create_time TIMESTAMP NOT NULL,
location_type SMALLINT,
deleted SMALLINT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 创建索引
CREATE INDEX idx_position_template_time ON position_template(create_time);
CREATE INDEX idx_position_template_biz_id ON position_template(biz_id);
-- log_template
CREATE TABLE log_template (
id BIGINT PRIMARY KEY,
content VARCHAR(1000),
operator_id BIGINT,
create_time TIMESTAMP NOT NULL,
log_level VARCHAR(20),
deleted SMALLINT DEFAULT 0
);
CREATE INDEX idx_log_template_time ON log_template(create_time);
CREATE INDEX idx_log_template_operator ON log_template(operator_id);
六、测试验证
启动项目后,通过以下方式验证:
-
插入测试 :调用
positionService.savePosition(),传入createTime为当前时间,查看PostgreSQL是否自动创建对应月表并插入数据 -
跨月查询 :调用
queryByCrossMonth(),查询跨月数据,查看控制台SQL是否同时查询多张表 -
分页测试 :调用
pageQuery(),验证分页结果和总条数是否正确 -
自动建表:修改cron表达式为当前时间,验证是否自动创建下月分表
-
监控验证 :访问
http://localhost:8080/sharding-demo/actuator/prometheus,查看指标是否正常暴露
七、总结
本文基于JDK17 + SpringBoot3 + ShardingSphere5实现了生产级的多表分库分表方案,核心优化点:
| 优化项 | 原方案问题 | 优化后方案 |
|---|---|---|
| 分库路由 | 依赖db_type字段,存在全库扫描风险 |
表级别直接指定数据源,零字段侵入 |
| 自动建表 | 硬编码SQL,维护成本高 | 模板表模式,自动继承索引和约束 |
| 监控能力 | 仅Druid监控 | 集成Prometheus + 分片执行指标 |
| 分页适配 | 固定MySQL方言 | DbType.AUTO动态识别 |
| 健壮性 | 无提前建表容错 | 提前创建下下月表,避免节假日失败 |
所有代码和配置均已测试通过,可直接复制使用。如需扩展新表,只需在actual-data-nodes中添加表名,并创建对应模板表即可,无需修改任何业务代码。
最后,觉得有用的话,欢迎点赞收藏,关注我,持续分享Java后端实战干货!