Spring Boot集成ShardingSphere,实现数据库分表

1,576 阅读5分钟

image.png

ShardingSphere功能介绍

ShardingSphere 是一个开源的分布式数据库中间件,旨在为应用提供数据库分片、读写分离、分布式事务等功能。它能够与现有的数据库无缝集成,并且支持多种数据库(包括 MySQL、SQL Server、Oracle 等),且无需对应用代码做太多改动。

官网:shardingsphere.apache.org/

ShardingSphere 提供以下核心功能:

  1. 分库分表 (Sharding)
  • 通过配置规则将数据划分到多个数据库或表中,常见的分片方式包括基于范围、哈希、复合字段等。
  • 支持多种分片策略,如按某个字段值分片(例如,基于 user_idorder_id 等字段),以及表和数据库的分片。
  1. 读写分离 (Read/Write Splitting)
  • 可以通过配置实现读操作与写操作分离。一般情况下,写操作指向主库,读操作可以从多个副本库进行负载均衡读取。
  1. 数据脱敏与加密 (Data Masking & Encryption)
  • 提供数据加密与脱敏功能,保护数据库中的敏感数据。
  1. 分布式事务 (Distributed Transaction)
  • 支持分布式事务,确保跨多个数据库操作时的一致性。
  1. 透明性与兼容性
  • ShardingSphere 是一个数据库中间件,能够透明地将分片策略应用到应用层。它支持与 Spring Boot、Spring Cloud、MyBatis、JPA 等框架的集成,应用层代码无需做额外改动。
  1. 支持多种数据库
  • ShardingSphere 支持 MySQL、PostgreSQL、SQL Server、Oracle 等常见数据库。可以灵活地选择需要支持的数据库。
  1. 高可扩展性
  • ShardingSphere 提供了扩展点,支持灵活的功能扩展与二次开发。

Spring Boot中使用ShardingSphere实现分表,并同时支持SQL Server、MySQL、Oracle、PostgreSQL

Spring Boot 中使用 ShardingSphere 实现分表,并同时支持 SQL ServerMySQLOraclePostgreSQL 数据库,需要进行以下步骤。通过配置 ShardingSphere 的分片策略,结合不同数据库的连接设置,可以实现跨多个数据库的数据分片。

步骤 1: 引入必要的依赖

pom.xml 文件中,添加 Spring BootShardingSphere 和不同数据库的 JDBC 驱动。

<dependencies>
    <!-- Spring Boot 基础依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- ShardingSphere-JDBC for Spring Boot -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        <version>5.0.0</version> <!-- 请根据需要选择合适的版本 -->
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!-- SQL Server 驱动 -->
    <dependency>
        <groupId>com.microsoft.sqlserver</groupId>
        <artifactId>mssql-jdbc</artifactId>
        <version>9.4.1.jre8</version>
    </dependency>

    <!-- Oracle 驱动 -->
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>19.8.0.0</version>
    </dependency>

    <!-- PostgreSQL 驱动 -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.5.0</version>
    </dependency>
</dependencies>

步骤 2: 配置 application.yml

application.yml 中,配置 ShardingSphere 相关数据源以及分片策略。

spring:
  datasource:
    # 配置 MySQL 数据源
    mysql:
      url: jdbc:mysql://localhost:3306/mysql_db
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

    # 配置 SQL Server 数据源
    sqlserver:
      url: jdbc:sqlserver://localhost:1433;databaseName=sqlserver_db
      username: sa
      password: password
      driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver

    # 配置 Oracle 数据源
    oracle:
      url: jdbc:oracle:thin:@localhost:1521:orcl
      username: oracle
      password: oracle
      driver-class-name: oracle.jdbc.OracleDriver

    # 配置 PostgreSQL 数据源
    postgresql:
      url: jdbc:postgresql://localhost:5432/postgresql_db
      username: postgres
      password: password
      driver-class-name: org.postgresql.Driver

  sharding:
    jdbc:
      config:
        data-source:
          mysql:
            url: jdbc:mysql://localhost:3306/mysql_db
            username: root
            password: root
            driver-class-name: com.mysql.cj.jdbc.Driver
          sqlserver:
            url: jdbc:sqlserver://localhost:1433;databaseName=sqlserver_db
            username: sa
            password: password
            driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
          oracle:
            url: jdbc:oracle:thin:@localhost:1521:orcl
            username: oracle
            password: oracle
            driver-class-name: oracle.jdbc.OracleDriver
          postgresql:
            url: jdbc:postgresql://localhost:5432/postgresql_db
            username: postgres
            password: password
            driver-class-name: org.postgresql.Driver

      rules:
        sharding:
          tables:
            order:
              actual-data-nodes: mysql.order_${0..1},sqlserver.order_${0..1},oracle.order_${0..1},postgresql.order_${0..1}
              table-strategy:
                inline:
                  sharding-column: order_id
                  algorithm-expression: order_${order_id % 2}
            user:
              actual-data-nodes: mysql.user_${0..1},sqlserver.user_${0..1},oracle.user_${0..1},postgresql.user_${0..1}
              table-strategy:
                inline:
                  sharding-column: user_id
                  algorithm-expression: user_${user_id % 2}

解释:

  • data-source: 定义了每个数据库的数据源,包括 MySQL、SQL Server、Oracle 和 PostgreSQL。
  • sharding: 配置了分片规则。每个表(如 orderuser)在不同数据库中都有实际的数据节点,例如 mysql.order_0, sqlserver.order_0 等。
  • table-strategy: 使用 inline 策略,依据 order_iduser_id 来进行分片,例如 order_id % 2 表示将数据分片为 order_0order_1

步骤 3: 配置 ShardingSphere 数据源和分片规则

你需要编写 Java 配置类来配置 ShardingSphere 数据源和分片规则。

ShardingConfig.java

@Configuration
@EnableTransactionManagement
public class ShardingConfig {

    @Bean
    public DataSource dataSource() throws SQLException {
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), createShardingRuleConfig());
    }

    private Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> dataSourceMap = new HashMap<>();
        dataSourceMap.put("mysql", createDataSource("mysql"));
        dataSourceMap.put("sqlserver", createDataSource("sqlserver"));
        dataSourceMap.put("oracle", createDataSource("oracle"));
        dataSourceMap.put("postgresql", createDataSource("postgresql"));
        return dataSourceMap;
    }

    private DataSource createDataSource(String dataSourceName) {
        HikariDataSource dataSource = new HikariDataSource();
        switch (dataSourceName) {
            case "mysql":
                dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mysql_db");
                dataSource.setUsername("root");
                dataSource.setPassword("root");
                dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
                break;
            case "sqlserver":
                dataSource.setJdbcUrl("jdbc:sqlserver://localhost:1433;databaseName=sqlserver_db");
                dataSource.setUsername("sa");
                dataSource.setPassword("password");
                dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
                break;
            case "oracle":
                dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:orcl");
                dataSource.setUsername("oracle");
                dataSource.setPassword("oracle");
                dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
                break;
            case "postgresql":
                dataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/postgresql_db");
                dataSource.setUsername("postgres");
                dataSource.setPassword("password");
                dataSource.setDriverClassName("org.postgresql.Driver");
                break;
            default:
                throw new IllegalArgumentException("Unsupported DataSource");
        }
        return dataSource;
    }

    private ShardingRuleConfiguration createShardingRuleConfig() {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();

        // 配置订单表的分片规则
        shardingRuleConfig.getTableRuleConfigs().add(createOrderTableRule());
        // 配置用户表的分片规则
        shardingRuleConfig.getTableRuleConfigs().add(createUserTableRule());

        // 设置默认数据源
        shardingRuleConfig.setDefaultDataSourceName("mysql");

        return shardingRuleConfig;
    }

    private TableRuleConfiguration createOrderTableRule() {
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
        orderTableRuleConfig.setLogicTable("order");
        orderTableRuleConfig.setActualDataNodes("mysql.order_${0..1},sqlserver.order_${0..1},oracle.order_${0..1},postgresql.order_${0..1}");
        orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "order_${order_id % 2}"));
        return orderTableRuleConfig;
    }

    private TableRuleConfiguration createUserTableRule() {
        TableRuleConfiguration userTableRuleConfig = new TableRuleConfiguration();
        userTableRuleConfig.setLogicTable("user");
        userTableRuleConfig.setActualDataNodes("mysql.user_${0..1},sqlserver.user_${0..1},oracle.user_${0..1},postgresql.user_${0..1}");
        userTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "user_${user_id % 2}"));
        return userTableRuleConfig;
    }
}

说明:

  • createDataSourceMap() 方法将所有数据源注册到 ShardingDataSourceFactory
  • createShardingRuleConfig() 方法定义了分片规则,分别为 orderuser 表指定了分片策略。
  • 分片策略通过 InlineShardingStrategyConfiguration 来设置,依据字段 order_iduser_id 进行分片。

步骤 4: 创建实体类

你需要根据业务需求定义实体类。例如:

@Entity
public class Order {

    @Id
    private Long orderId;
    private String orderDetails;

    // getters and setters
}

@Entity
public class User {

    @Id
    private Long userId;
    private String userName;

    // getters and setters
}

步骤 5: 测试

创建一些简单的测试用例,来验证 ShardingSphere 的分片是否按预期工作。你可以通过执行一些简单的 CRUD 操作来检查分片效果。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingTest {

    @Autowired
    private OrderRepository orderRepository;

    @Test
    public void testOrderSharding() {
        Order order = new Order();
        order.setOrderId(1L);
        order.setOrderDetails("Test order");
        orderRepository.save(order);

        Optional<Order> savedOrder = orderRepository.findById(1L);
        assertTrue(savedOrder.isPresent());
    }
}

总结

通过上面的配置,ShardingSphere 能够实现跨多个数据库的分片,包括 MySQL、SQL Server、Oracle 和 PostgreSQL。在实际应用中,你可以根据需要调整分片规则,结合数据源来实现分布式数据管理。