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.
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: true4. 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.
6. Source Code Repository
Git repository: https://gitee.com/luowenjie98/sharing-sphere-mybatisplus-demo
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
