Spring Boot 分库分表策略示例

分库分表是为了应对大规模数据和高并发请求,提高系统的性能和可扩展性。以下是如何在 Spring Boot 中实现分库分表的详细策略:

1. 分库策略

分库策略是将数据分散到多个数据库实例中。常见的分库策略有:

  • 按用户 ID:例如,通过用户 ID 的哈希值决定存储到哪个数据库。

  • 按业务类型:不同的业务或数据类型存储到不同的数据库。

  • 按数据量:根据数据量将数据分散到多个数据库中。

实现步骤

  • 配置多个数据源

    application.yml 文件中配置多个数据源的连接信息。

    示例配置:

    复制代码
    spring:
      datasource:
        dynamic:
          primary: db1
          datasource:
            db1:
              url: jdbc:mysql://localhost:3306/db1
              username: root
              password: password
            db2:
              url: jdbc:mysql://localhost:3306/db2
              username: root
              password: password
            # 添加更多数据源
  • 动态数据源路由

    创建 DynamicDataSource 类,继承 AbstractRoutingDataSource,在 determineCurrentLookupKey 方法中返回当前的数据源标识。

    DataSourceContextHolder 类用于存储当前的数据库标识。

    复制代码
     public class DynamicDataSource extends AbstractRoutingDataSource {
         @Override
         protected Object determineCurrentLookupKey() {
             return DataSourceContextHolder.getDataSourceType();
         }
     }
    ​
     public class DataSourceContextHolder {
         private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    ​
         public static void setDataSourceType(String dataSourceType) {
             contextHolder.set(dataSourceType);
         }
    ​
         public static String getDataSourceType() {
             return contextHolder.get();
         }
    ​
         public static void clearDataSourceType() {
             contextHolder.remove();
         }
     }
  • 根据用户 ID 选择数据源

    使用工具类 DataSourceUtil 根据用户 ID 计算出数据源标识。

    复制代码
     public class DataSourceUtil {
         private static final int TOTAL_DATASOURCES = 8;
    ​
         public static String getDataSourceNameByUserId(Long userId) {
             int index = (int) (userId % TOTAL_DATASOURCES) + 1;
             return "db" + index;
         }
     }
  • 配置数据源

    在配置类中创建 DynamicDataSource 实例,并配置各个数据源。

    复制代码
     @Configuration
     public class DataSourceConfig {
         @Autowired
         @Qualifier("db1DataSource")
         private DataSource db1DataSource;
    ​
         @Autowired
         @Qualifier("db2DataSource")
         private DataSource db2DataSource;
    ​
         // 更多数据源...
    ​
         @Bean
         public DataSource dataSource() {
             DynamicDataSource dynamicDataSource = new DynamicDataSource();
             
             Map<Object, Object> targetDataSources = new HashMap<>();
             targetDataSources.put("db1", db1DataSource);
             targetDataSources.put("db2", db2DataSource);
             // 更多数据源...
    ​
             dynamicDataSource.setTargetDataSources(targetDataSources);
             dynamicDataSource.setDefaultTargetDataSource(db1DataSource);
             
             return dynamicDataSource;
         }
    ​
         @Bean
         public PlatformTransactionManager transactionManager() {
             return new DataSourceTransactionManager(dataSource());
         }
     }

2. 分表策略

分表策略是将数据分散到多个表中。常见的分表策略有:

  • 按时间分表:例如,每个月一个表。

  • 按 ID 范围分表:例如,每 10000 条数据一个表。

  • 按用户 ID 哈希:例如,将用户数据分散到多个表中。

实现步骤

  1. 生成表名

    创建工具类 TableNameUtil 根据分表策略生成表名。

    复制代码
     public class TableNameUtil {
         public static String getTableNameByMonth(String baseTableName, LocalDate date) {
             String month = date.format(DateTimeFormatter.ofPattern("yyyy_MM"));
             return baseTableName + "_" + month;
         }
    ​
         public static String getTableNameByIdRange(String baseTableName, Long id) {
             int range = (int) (id / 10000);
             return baseTableName + "_" + range;
         }
    ​
         public static String getTableNameByUserId(String baseTableName, Long userId) {
             int tableIndex = (int) (userId % 8);
             return baseTableName + "_" + tableIndex;
         }
     }
  2. 在数据访问层使用分表策略

    在数据访问层根据生成的表名执行数据库操作。

    复制代码
     @Repository
     public class OrderRepository {
         private final JdbcTemplate jdbcTemplate;
    ​
         public OrderRepository(JdbcTemplate jdbcTemplate) {
             this.jdbcTemplate = jdbcTemplate;
         }
    ​
         public void saveOrder(Order order) {
             String dataSourceName = DataSourceUtil.getDataSourceNameByUserId(order.getUserId());
             DataSourceContextHolder.setDataSourceType(dataSourceName);
    ​
             String tableName = TableNameUtil.getTableNameByUserId("orders", order.getUserId());
             String sql = "INSERT INTO " + tableName + " (id, order_date, amount) VALUES (?, ?, ?)";
             jdbcTemplate.update(sql, order.getId(), order.getOrderDate(), order.getAmount());
    ​
             DataSourceContextHolder.clearDataSourceType();
         }
     }

总结

  • 分库:将数据存储到多个数据库中,通过动态数据源选择和路由来决定当前使用的数据库。

  • 分表:将数据存储到多个表中,根据分表策略生成动态表名。

  • 实现:配置多个数据源,使用动态数据源路由,创建工具类生成表名,并在数据访问层应用这些策略。

这种分库分表策略可以有效地提高系统的性能和可扩展性,尤其适用于大规模数据处理场景。

相关推荐
kfaino42 分钟前
码农的AI翻身(六)你好,我叫 Parameter
后端·aigc
掘金者阿豪44 分钟前
把业务数据变成共享仪表盘:Metabase可视化与远程访问实践
前端·后端
猪猪拆迁队2 小时前
虚拟工厂仿真引擎的架构设计:让一条产线可编程、可观测、可干预
后端·ai编程
字节跳动数据库2 小时前
文章分享——相似函数处理方法
人工智能·后端·程序员
云技纵横2 小时前
@Transactional 失效的 7 种场景:第 5 种最难排查
后端
用户6757049885023 小时前
你知道 Go 结构体和结构体指针调用的区别吗?一文带你彻底搞懂!
后端·go
程序员cxuan3 小时前
读懂 Claude Code 架构分析系列,第一篇,开始!
人工智能·后端·架构
用户6757049885023 小时前
面试官问“装饰器模式”,这样回答薪资多要 3000!
后端
tntxia3 小时前
Geo Scene域名修改引起的一些问题
后端
用户298698530143 小时前
Java 实现 Word 文档加密与权限解除
java·后端