Databases 14 min read

Integrating MyBatis-Plus Dynamic DataSource with ShardingSphere-JDBC and Custom Load Balancing

This guide shows how to combine MyBatis-Plus dynamic data source routing with ShardingSphere-JDBC for horizontal sharding and read‑write splitting, including Maven dependencies, YAML configuration, Spring bean setup, and a custom load‑balancing algorithm to keep @DS annotations functional.

Java Captain
Java Captain
Java Captain
Integrating MyBatis-Plus Dynamic DataSource with ShardingSphere-JDBC and Custom Load Balancing
Background: The original project used MyBatis-Plus dynamic data sources with @DS for read/write routing. As table sizes grew, horizontal sharding with ShardingJDBC was needed, but integrating both caused conflicts because most tutorials treat Sharding as a single data source, breaking @DS usage. This article presents a working solution.

1. Version Selection

ShardingJDBC has two main versions: the early Sharding-JDBC and the newer ShardingSphere-JDBC component of the ShardingSphere project.

Sharding-JDBC: released in 2016 as a lightweight JDBC layer for sharding and read‑write splitting.

ShardingSphere: evolved from Sharding-JDBC, released in 2018, provides a full distributed database ecosystem (Sharding-JDBC, Sharding-Proxy, Sharding-Sidecar, etc.).

The standalone ShardingJDBC is no longer maintained; the most commonly used version is 4.1.1.

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency>

ShardingSphere-JDBC is now the active project; we use version 5.2.1.

Official documentation: https://www.bookstack.cn/read/shardingsphere-5.1.0-zh/ecf18b21ab3f559c.md

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.2.1</version>
</dependency>

2. Project Dependencies

All Maven dependencies required for the demo:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>3.4.5</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.0</version>
    </dependency>
    <!-- Read‑write splitting -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.3.2</version>
    </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-spring-boot-starter</artifactId>
        <version>5.2.1</version>
        <exclusions>
            <exclusion>
                <groupId>org.yaml</groupId>
                <artifactId>snakeyaml</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- Add correct version of SnakeYAML required by ShardingSphere -->
    <dependency>
        <groupId>org.yaml</groupId>
        <artifactId>snakeyaml</artifactId>
        <version>1.33</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

3. Parameter Configuration

application.yml configuration for server, MyBatis‑Plus, Spring, sharding rules, read‑write splitting and SQL show.

server:
  port: 8080
mybatis-plus:
  mapper-locations: classpath*:mybatis/*.xml
  type-aliases-package: com.game.sharding.dto
  configuration:
    map-underscore-to-camel-case: false
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
spring:
  application:
    name: sharding-jdbc-test
  sharding-sphere:
    datasource:
      names: master,write,read,read2
      master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      write:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      read:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev_read?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      read2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/game_dev_read?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
    rules:
      sharding:
        tables:
          team_msg:
            actual-data-nodes: customer-ds.team_msg_${0..1}
            table-strategy:
              standard:
                sharding-column: id
                sharding-algorithm-name: msg-id
        sharding-algorithms:
          msg-id:
            type: INLINE
            props:
              algorithm-expression: team_msg_${id % 2}
      readwrite-splitting:
        data-sources:
          customer-ds:
            load-balancer-name: customer-lb
            static-strategy:
              write-data-source-name: master
              read-data-source-names: read,read2,write
        load-balancers:
          customer-lb:
            type: CUSTOM
      props:
        sql-show: true

4. Code Configuration

The key is to register the MyBatis‑Plus data source as a ShardingSphere‑JDBC data source and expose four dynamic data source names (master, write, read, read2) so that the @DS annotation can locate them.

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.driver.jdbc.adapter.AbstractDataSourceAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class MyDataSourceConfiguration {

    /** mybatisplus dynamic datasource properties */
    @Autowired
    private DynamicDataSourceProperties properties;

    /** shardingjdbc datasource */
    @Lazy
    @Resource(name = "shardingSphereDataSource")
    private AbstractDataSourceAdapter shardingSphereDataSource;

    @Value("${spring.sharding-sphere.datasource.names}")
    private String shardingDataSourceNames;

    /** Register dynamic datasource so that @DS works with shardingjdbc */
    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        if (StringUtils.isBlank(shardingDataSourceNames)) {
            throw new RuntimeException("配置 spring.sharding-sphere.datasource.names 不能为空");
        }
        String[] names = shardingDataSourceNames.split(",");
        return new AbstractDataSourceProvider() {
            @Override
            public Map<String, DataSource> loadDataSources() {
                Map<String, DataSource> dataSourceMap = new HashMap<>();
                Arrays.stream(names).forEach(name -> dataSourceMap.put(name, shardingSphereDataSource));
                return dataSourceMap;
            }
        };
    }

    /** Set the dynamic datasource as primary */
    @Primary
    @Bean
    public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
        dataSource.setPrimary(properties.getPrimary());
        dataSource.setStrict(properties.getStrict());
        dataSource.setStrategy(properties.getStrategy());
        dataSource.setProvider(dynamicDataSourceProvider);
        dataSource.setP6spy(properties.getP6spy());
        dataSource.setSeata(properties.getSeata());
        return dataSource;
    }
}

5. Custom Complex Load‑Balancing Algorithm

ShardingSphere loads load‑balance algorithms via SPI. Implement ReadQueryLoadBalanceAlgorithm and register the class in META-INF/services/org.apache.shardingsphere.readwritesplitting.spi.ReadQueryLoadBalanceAlgorithm .

Implementation example:

public class CustomLoadBalanceAlgorithm implements ReadQueryLoadBalanceAlgorithm {
    private Properties props;

    public CustomLoadBalanceAlgorithm() {}

    @Override
    public void init(Properties props) {
        this.props = props;
    }

    @Override
    public String getDataSource(String name, String writeDataSourceName,
                               List<String> readDataSourceNames, TransactionConnectionContext context) {
        // Get the datasource key set by @DS
        String dsKey = DynamicDataSourceContextHolder.peek();
        if (StringUtils.isNotBlank(dsKey)) {
            if (writeDataSourceName.equals(dsKey)) {
                return dsKey;
            }
            if (readDataSourceNames.contains(dsKey)) {
                return dsKey;
            }
            throw new RuntimeException("@DS 配置错误,当前数据源[" + dsKey + "]不在SharingJDBC数据源列表[" + readDataSourceNames + "]中");
        }
        return writeDataSourceName;
    }

    @Override
    public String getType() {
        return "CUSTOM";
    }

    @Override
    public boolean isDefault() {
        return true;
    }

    @Override
    public Properties getProps() {
        return this.props;
    }
}

After adding the service file and the class, ShardingSphere will use the custom algorithm, and the MyBatis‑Plus @DS annotation works seamlessly with sharding.

image
image
image
image
image
image
image
image

6. Source Code Repository

Git repository: https://gitee.com/luowenjie98/sharing-sphere-mybatisplus-demo

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

read/write splittingShardingSphereMybatis-Plusdynamic-datasourceCustom Load Balancer
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.