一、自定义多数据源方式
多数据源复制配置类即可。
1.1 Java配置类
package com.xx.wholesale.merchant.config.datasource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.io.FileNotFoundException;
@Configuration
@MapperScan(value = "com.xx.wholesale.merchant" + MerchantDataSourceConfig.DATA_SOURCE_SUB_NAME + ".dao",
sqlSessionFactoryRef = MerchantDataSourceConfig.DATA_SOURCE_SUB_NAME + "SqlSessionFactory",
sqlSessionTemplateRef = MerchantDataSourceConfig.DATA_SOURCE_SUB_NAME + "SqlSessionTemplate"
)
public class MerchantDataSourceConfig {
static final String DATA_SOURCE_SUB_NAME = "merchant";
@Bean(value = DATA_SOURCE_SUB_NAME + "DataSource")
@ConfigurationProperties(prefix = "spring.datasource." + DATA_SOURCE_SUB_NAME)
public HikariDataSource dataSource() {
return new HikariDataSource();
}
@Bean(value = DATA_SOURCE_SUB_NAME + "SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier(value = DATA_SOURCE_SUB_NAME + "DataSource") DataSource dataSource) throws Exception {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setConfigLocation(resourceLoader.getResource("classpath:mybatis-config.xml"));
Resource[] resources = null;
try {
resources = resolver.getResources("classpath:mapper/" + DATA_SOURCE_SUB_NAME + "/*.xml");
} catch (FileNotFoundException e) {
resources = new Resource[0];
}
factory.setMapperLocations(resources);
MybatisPlusInterceptor paginationInterceptor = new MybatisPlusInterceptor();
paginationInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
factory.setPlugins(paginationInterceptor);
return factory.getObject();
}
@Bean(value = DATA_SOURCE_SUB_NAME + "SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier(value = DATA_SOURCE_SUB_NAME + "SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
return sqlSessionTemplate;
}
@Bean(value = DATA_SOURCE_SUB_NAME + "TransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier(value = DATA_SOURCE_SUB_NAME + "DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2.2 配置
application.yml
spring:
datasource:
merchant:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.30.20.205:6033/le_shou?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true&useAffectedRows=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 连接池最大连接数,默认是10
maximum-pool-size: 30
minimum-idle: 2
max-lifetime: 7200000
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 300000
validation-timeout: 1000
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
connection-timeout: 3000
connection-test-query: select 1
auto-commit: true
二、结合Sharding-JDBC做多数据源
基础描述
springboot
:2.7.x
shardingsphere-jdbc-core
:5.4.x
- 数据源配置不建议使用类
YamlShardingSphereDataSourceFactory
中的类似YamlDataSourceConfigurationSwapper.swapToDataSources()
初始化生成,因为内部有连接池字段独立命名和映射,如果不了解内部源码可能会配置失败或报错,消耗排查时间- 官方文档:https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/yaml-config/rules/sharding/
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.17</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xx.wholesale.merchant</groupId>
<artifactId>wholesale-merchant</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>wholesale-merchant</name>
<description>wholesale-merchant</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<mysql-connector-java.version>8.0.17</mysql-connector-java.version>
<mybatis-spring-boot-starter.version>2.3.1</mybatis-spring-boot-starter.version>
<mybatis-plus-boot-starter.version>3.5.4.1</mybatis-plus-boot-starter.version>
<shardingsphere-jdbc-core.version>5.4.1</shardingsphere-jdbc-core.version>
<snakeyaml.version>1.33</snakeyaml.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>${shardingsphere-jdbc-core.version}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- MySQL Connector/J -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml相关配置
server:
port: 8899
tomcat:
basedir: ./
uri-encoding: UTF-8
max-threads: 1000
min-spare-threads: 30
accesslog:
enabled: true
directory: ${logging.file.path}
pattern: "%h %l %u %t %r %s %b %D"
spring:
application:
name: wholesale-merchant
profiles:
include: jdbc
logging:
config: classpath:log4j2_config.xml
file:
name: ${spring.application.name}
path: logs
mybatis-plus:
global-config:
db-config:
id-type: auto
table-underline: true
application-jdbc.yml配置
spring:
datasource:
bdata:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/bus_data?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 连接池最大连接数,默认是10
maximum-pool-size: 30
minimum-idle: 2
max-lifetime: 7200000
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 300000
validation-timeout: 1000
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
connection-timeout: 3000
connection-test-query: select 1
auto-commit: true
shardingsphere:
busorder:
mode:
type: standalone
repository:
type: JDBC
data-sources:
bus_order_0:
driver-class-name: com.mysql.cj.jdbc.Driver
# 此配置使用YamlDataSourceConfigurationSwapper.swapToDataSources()生成Map<String,DataSource>使用
# dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://127.0.0.1:3306/bus_order_0?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 连接池最大连接数,默认是10
maximum-pool-size: 30
minimum-idle: 2
max-lifetime: 7200000
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 300000
validation-timeout: 1000
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
connection-timeout: 3000
connection-test-query: select 1
auto-commit: true
bus_order_1:
driver-class-name: com.mysql.cj.jdbc.Driver
# dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://127.0.0.1:3306/bus_order_1?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 连接池最大连接数,默认是10
maximum-pool-size: 30
minimum-idle: 2
max-lifetime: 7200000
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 300000
validation-timeout: 1000
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
connection-timeout: 3000
connection-test-query: select 1
auto-commit: true
rules:
# - type: org.apache.shardingsphere.sharding.yaml.config.YamlShardingRuleConfiguration
sharding:
key-generators:
snowflake:
type: SNOWFLAKE
sharding-algorithms:
db_choose_bus_order_algorithm:
type: INLINE
props:
algorithm-expression: bus_order_${user_id % 2}
db_choose_account_algorithm:
type: INLINE
props:
algorithm-expression: bus_order_${user_id % 2}
tb_order_algorithm:
type: ORDER_ALGORITHM
# type: INLINE
# props:
# algorithm-expression: t_order_${order_id % 2}
default-database-strategy:
standard:
# 分片列名称
sharding-column: user_id
# 分片算法名称
sharding-algorithm-name: db_choose_bus_order_algorithm
tables:
t_order:
actual-data-nodes: bus_order_${0..1}.t_order_${0..1}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: tb_order_algorithm
t_account:
actual-data-nodes: bus_order_${0..1}.t_account
databaseStrategy:
shardingColumn: user_id
shardingAlgorithmName: db_choose_account_algorithm
# 展示修改以后的sql语句
props:
sql-show: true
DataSource相关配置
- BusDataDataSourceConfig.java
package com.xx.wholesale.merchant.config.datasource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.io.FileNotFoundException;
@Configuration
@MapperScan(value = "com.xx.wholesale.merchant." + BusDataDataSourceConfig.DATA_SOURCE_SUB_NAME + ".dao",
sqlSessionFactoryRef = BusDataDataSourceConfig.DATA_SOURCE_SUB_NAME + "SqlSessionFactory",
sqlSessionTemplateRef = BusDataDataSourceConfig.DATA_SOURCE_SUB_NAME + "SqlSessionTemplate"
)
public class BusDataDataSourceConfig {
static final String DATA_SOURCE_SUB_NAME = "busdata";
@Bean(value = DATA_SOURCE_SUB_NAME + "DataSource")
@ConfigurationProperties(prefix = "spring.datasource." + DATA_SOURCE_SUB_NAME)
public HikariDataSource dataSource() {
return new HikariDataSource();
}
@Bean(value = DATA_SOURCE_SUB_NAME + "SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier(value = DATA_SOURCE_SUB_NAME + "DataSource") DataSource dataSource) throws Exception {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setConfigLocation(resourceLoader.getResource("classpath:mybatis-config.xml"));
Resource[] resources = null;
try {
resources = resolver.getResources("classpath:mapper/" + DATA_SOURCE_SUB_NAME + "/*.xml");
} catch (FileNotFoundException e) {
resources = new Resource[0];
}
factory.setMapperLocations(resources);
MybatisPlusInterceptor paginationInterceptor = new MybatisPlusInterceptor();
paginationInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
factory.setPlugins(paginationInterceptor);
return factory.getObject();
}
@Bean(value = DATA_SOURCE_SUB_NAME + "SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier(value = DATA_SOURCE_SUB_NAME + "SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
return sqlSessionTemplate;
}
@Bean(value = DATA_SOURCE_SUB_NAME + "TransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier(value = DATA_SOURCE_SUB_NAME + "DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
- BusOrderNodeDataSourceConfig.java
package com.xx.wholesale.merchant.config.datasource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.shardingsphere.driver.api.yaml.YamlJDBCConfiguration;
import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory;
import org.apache.shardingsphere.infra.yaml.config.swapper.resource.YamlDataSourceConfigurationSwapper;
import org.apache.shardingsphere.sharding.yaml.config.YamlShardingRuleConfiguration;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
@MapperScan(value = "com.xx.wholesale.merchant." + BusOrderNodeDataSourceConfig.DATA_SOURCE_SUB_NAME + ".dao",
sqlSessionFactoryRef = BusOrderNodeDataSourceConfig.DATA_SOURCE_SUB_NAME + "SqlSessionFactory",
sqlSessionTemplateRef = BusOrderNodeDataSourceConfig.DATA_SOURCE_SUB_NAME + "SqlSessionTemplate"
)
public class BusOrderNodeDataSourceConfig {
static final String DATA_SOURCE_SUB_NAME = "busorder";
@ConfigurationProperties(prefix = "spring.shardingsphere." + DATA_SOURCE_SUB_NAME + ".rules.sharding")
@Bean(value = DATA_SOURCE_SUB_NAME + "YamlShardingRuleConfiguration")
public YamlShardingRuleConfiguration yamlShardingRuleConfiguration() {
return new YamlShardingRuleConfiguration();
}
@ConfigurationProperties(prefix = "spring.shardingsphere." + DATA_SOURCE_SUB_NAME)
@Bean(value = DATA_SOURCE_SUB_NAME + "YamlJDBCConfiguration")
public YamlJDBCConfiguration yamlJDBCConfiguration(@Qualifier(value = DATA_SOURCE_SUB_NAME + "YamlShardingRuleConfiguration") YamlShardingRuleConfiguration yamlShardingRuleConfiguration) {
YamlJDBCConfiguration yamlJDBCConfiguration = new YamlJDBCConfiguration();
yamlJDBCConfiguration.getRules().add(yamlShardingRuleConfiguration);
return yamlJDBCConfiguration;
}
@ConfigurationProperties(prefix = "spring.shardingsphere." + DATA_SOURCE_SUB_NAME + ".data-sources")
@Bean(value = DATA_SOURCE_SUB_NAME + "HikariDataSourceMap")
public Map<String, HikariDataSource> dataSourcesMap() {
return new LinkedHashMap<>();
}
@Bean(value = DATA_SOURCE_SUB_NAME + "DataSource")
public DataSource dataSource(@Qualifier(value = DATA_SOURCE_SUB_NAME + "HikariDataSourceMap") Map<String, HikariDataSource> dataSourcesMap
,@Qualifier( DATA_SOURCE_SUB_NAME + "YamlJDBCConfiguration") YamlJDBCConfiguration yamlJDBCConfiguration) throws Exception {
Class<YamlShardingSphereDataSourceFactory> calzz = YamlShardingSphereDataSourceFactory.class;
Field field = calzz.getDeclaredField("DATA_SOURCE_SWAPPER");
Method method = calzz.getDeclaredMethod("createDataSource", Map.class, YamlJDBCConfiguration.class);
field.setAccessible(true);
method.setAccessible(true);
YamlDataSourceConfigurationSwapper dataSourceConfigurationSwapper = (YamlDataSourceConfigurationSwapper) field.get(null);
// 如用官方生成DataSource,需注意类HikariDataSourcePoolMetaData中配置映射和StorageResourceUtils,特别是url和jdbcUrl
//return (DataSource) method.invoke(null, dataSourceConfigurationSwapper.swapToDataSources(yamlJDBCConfiguration.getDataSources()), yamlJDBCConfiguration);
return (DataSource) method.invoke(null, dataSourcesMap, yamlJDBCConfiguration);
}
@Bean(value = DATA_SOURCE_SUB_NAME + "SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier(value = DATA_SOURCE_SUB_NAME + "DataSource") DataSource dataSource) throws Exception {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setConfigLocation(resourceLoader.getResource("classpath:mybatis-config.xml"));
Resource[] resources = null;
try {
resources = resolver.getResources("classpath:mapper/" + DATA_SOURCE_SUB_NAME + "/*.xml");
} catch (FileNotFoundException e) {
resources = new Resource[0];
}
factory.setMapperLocations(resources);
MybatisPlusInterceptor paginationInterceptor = new MybatisPlusInterceptor();
paginationInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
factory.setPlugins(paginationInterceptor);
return factory.getObject();
}
@Bean(value = DATA_SOURCE_SUB_NAME + "SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier(value = DATA_SOURCE_SUB_NAME + "SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
return sqlSessionTemplate;
}
@Bean(value = DATA_SOURCE_SUB_NAME + "TransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier(value = DATA_SOURCE_SUB_NAME + "DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
- OrderShardingAlgorithm.java
package com.xx.wholesale.merchant.config.util;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import java.util.Collection;
/**
* 自定义订单分表策略实现
*/
public class OrderShardingAlgorithm implements StandardShardingAlgorithm<String> {
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
return "t_order_" + Long.valueOf(preciseShardingValue.getValue()) % 2;
}
@Override
public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
return null;
}
@Override
public String getType() {
return "ORDER_ALGORITHM";
}
}
- SPI配置
在src/main/resources/
下创建文件夹META-INF/services
,并创建文org.apache.shardingsphere.sharding.spi.ShardingAlgorithm
,内容如下:
com.xx.wholesale.merchant.config.util.OrderShardingAlgorithm
示例
- 数据库
CREATE DATABASE bus_data CHARACTER SET = utf8;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`user_id` bigint(20) NOT NULL,
`user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_user` VALUES (1, 'jon', '2023-11-25 19:59:55');
INSERT INTO `t_user` VALUES (2, '第三眼的思绪', '2023-11-25 20:12:32');
CREATE DATABASE bus_order_0 CHARACTER SET = utf8;
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account` (
`user_id` bigint(20) NOT NULL,
`amount` bigint(20) NOT NULL DEFAULT 0 COMMENT '账户余额',
`consume_amount` bigint(20) NOT NULL COMMENT '消费金额',
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户账户表' ROW_FORMAT = Dynamic;
INSERT INTO `t_account` VALUES (1, 10, 20, '2023-11-25 20:16:17');
DROP TABLE IF EXISTS `t_order_0`;
CREATE TABLE `t_order_0` (
`order_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_id` bigint(20) NOT NULL,
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_order_0` VALUES ('002000', 2, '2023-11-25 20:08:00');
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_id` bigint(20) NOT NULL,
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `t_order_1` VALUES ('002001', 2, '2023-11-25 20:09:18');
CREATE DATABASE bus_order_1 CHARACTER SET = utf8;
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account` (
`user_id` bigint(20) NOT NULL,
`amount` bigint(20) NOT NULL DEFAULT 0 COMMENT '账户余额',
`consume_amount` bigint(20) NOT NULL COMMENT '消费金额',
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户账户表' ROW_FORMAT = DYNAMIC;
INSERT INTO `t_account` VALUES (1, 20, 40, '2023-11-25 20:16:17');
DROP TABLE IF EXISTS `t_order_0`;
CREATE TABLE `t_order_0` (
`order_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_id` bigint(20) NOT NULL,
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
INSERT INTO `t_order_0` VALUES ('001000', 1, '2023-11-25 20:08:00');
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_id` bigint(20) NOT NULL,
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
INSERT INTO `t_order_1` VALUES ('001001', 1, '2023-11-25 20:09:18');
- 生成如下com.xx.wholesale.merchant.busorder.dao.OrderDao文件
package com.xx.wholesale.merchant.busorder.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
@Mapper
public interface OrderDao extends BaseMapper {
@Select(value = "select * from t_order where user_id=#{userId} and order_id=#{orderId} limit 1")
public List<Map<String, Object>> queryOrder(@Param("userId") Long userId, @Param("orderId") String orderId);
@Select(value = "select * from t_account where user_id=#{userId} limit 1")
public Map<String, Object> queryAccount(@Param("userId") Long userId);
}
- 生成如下com.xx.wholesale.merchant.busdata.dao.UserDao文件
package com.xx.wholesale.merchant.busdata.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.Map;
@Mapper
public interface UserDao extends BaseMapper {
@Select(value = "select * from t_user where user_id=#{userId} limit 1")
public Map<String, Object> selectOne(@Param("userId") Long userId);
}
- 测试类
package com.xx.wholesale.merchant;
import com.xx.wholesale.merchant.busdata.dao.UserDao;
import com.xx.wholesale.merchant.busorder.dao.OrderDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class WholesaleMerchantApplicationTests {
@Autowired
private OrderDao orderDao;
@Autowired
private UserDao bindDevicerDao;
/**
* 【分库分表】
* 查询既分了库又分了表的订单
*/
@Test
void queryOrderShardingLoads() {
List<Map<String, Object>> map = orderDao.queryOrder(1L, "001000");
System.out.println(map);
}
/**
* 【分库未分表】
* 查询用户账户信息,分库但未分表
*/
@Test
void queryAccountShardingLoads() {
Map<String, Object> map = orderDao.queryAccount(1L);
System.out.println(map);
}
/**
* 【未分库分表】
* 查询用户基础信息
*/
@Test
void queryUserShardingLoads() {
Map<String, Object> map = bindDevicerDao.selectOne(1L);
System.out.println(map);
}
}