Spring Boot에서 Dynamic Datasource와 ShardingSphere JDBC를 통한 기존 데이터소스 주도적 사용 및 분할 테이블 구현

종속성 설정

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.6.1</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.15</version>
</dependency>

데이터소스 구성

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  datasource:
    url: jdbc:mysql://localhost:3306/primary_db?serverTimezone=UTC
    username: admin
    password: secure_pass
  shardingsphere:
    mode:
      type: Memory
    props:
      sql-show: true
    datasource:
      names: shard_db
      shard_db:
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://localhost:3306/shard_db?serverTimezone=UTC
        username: shard_user
        password: shard_pass
    rules:
      sharding:
        tables:
          transaction_log:
            actual-data-nodes: shard_db.transaction_$->{2023..2024}
            table-strategy:
              standard:
                sharding-column: log_date
                sharding-algorithm-name: date-sharding
            key-generate-strategy:
              column: record_id
              key-generator-name: id-generator
        sharding-algorithms:
          date-sharding:
            type: DATE_BASED_SHARDING
            props:
              sharding-pattern: "transaction_$->{log_date.getYear()}"
        key-generators:
          id-generator:
            type: SNOWFLAKE

데이터소스 통합 구성 클래스

@Configuration
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class})
public class DatasourceConfig {

    @Autowired
    private DynamicDataSourceProperties dsProps;
    
    @Autowired
    private DataSourceProperties primaryProps;
    
    @Resource(name = "shardingSphereDataSource")
    private AbstractDataSourceAdapter shardingDS;

    @Bean
    public DynamicDataSourceProvider dataSourceProvider() {
        DataSourceProperty mainProperty = new DataSourceProperty();
        mainProperty.setUrl(primaryProps.getUrl())
                   .setUsername(primaryProps.getUsername())
                   .setPassword(primaryProps.getPassword());
                   
        return new ShardingDSProvider(mainProperty, dsProps, shardingDS);
    }

    @Primary
    @Bean
    public DataSource dynamicDataSource() {
        DynamicRoutingDataSource ds = new DynamicRoutingDataSource();
        ds.setPrimary(dsProps.getPrimary());
        return ds;
    }
}

@AllArgsConstructor
class ShardingDSProvider extends AbstractDataSourceProvider {
    private final DataSourceProperty mainProperty;
    private final DynamicDataSourceProperties dsProps;
    private final AbstractDataSourceAdapter shardingAdapter;
    private static final String SHARD_DS_NAME = "shard_db";

    @Override
    public Map<String, DataSource> loadDataSources() {
        Map<String, DataSourceProperty> properties = new HashMap<>();
        properties.put(dsProps.getPrimary(), mainProperty);
        properties.putAll(dsProps.getDatasource());
        
        Map<String, DataSource> dsMap = createDataSourceMap(properties);
        dsMap.put(SHARD_DS_NAME, shardingAdapter);
        return dsMap;
    }
}

사용자 정의 분할 알고리즘

public class DateBasedSharding implements StandardShardingAlgorithm<LocalDateTime> {
    
    private String shardingPattern;
    
    @Override
    public void init() {
        shardingPattern = getRequiredProperty("sharding-pattern");
    }

    @Override
    public String doSharding(Collection<String> tables, 
                             PreciseShardingValue<LocalDateTime> value) {
        return evaluateExpression(value.getValue(), value.getColumnName());
    }

    @Override
    public Collection<String> doSharding(Collection<String> tables, 
                                        RangeShardingValue<LocalDateTime> range) {
        LocalDateTime start = range.getValueRange().lowerEndpoint();
        LocalDateTime end = range.getValueRange().upperEndpoint();
        List<String> matchedTables = new ArrayList<>();
        
        int startYear = start.getYear();
        int endYear = end.getYear();
        
        for (int year = startYear; year <= endYear; year++) {
            String tableName = "transaction_" + year;
            if (tables.contains(tableName)) {
                matchedTables.add(tableName);
            }
        }
        return matchedTables.isEmpty() ? tables : matchedTables;
    }

    private String evaluateExpression(LocalDateTime date, String column) {
        return shardingPattern.replace("$->{log_date.getYear()}", 
                String.valueOf(date.getYear()));
    }
    
    private String getRequiredProperty(String key) {
        return Optional.ofNullable(props.getProperty(key))
                .orElseThrow(() -> new IllegalArgumentException(key + " is required"));
    }
}

알고리즘 등록

src/main/resources/META-INF/services/org.apache.shardingsphere.sharding.spi.ShardingAlgorithm 파일 생성 후:

com.example.DateBasedSharding

주요 고려사항

  • 기존 데이터소스는 primary_db로 설정됨
  • 분할 테이블 전용 데이터소스: shard_db
  • 분할 키: log_date (LocalDateTime 타입)
  • 분할 테이블 명명 규칙: transaction_YYYY

태그: Spring Boot Dynamic Datasource ShardingSphere Database Sharding DataSource Routing

6월 23일 18:37에 게시됨