注意:分库分表要注意id不能再用数据库自增方式。可以采用雪花算法(新增的表),自定义分片算法(旧表)
分片策略配置
对于分片策略存有数据源分片策略和表分片策略两种维度
对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源
表:
CREATE TABLE `t_user0` (
`id` bigint(20) NOT NULL,
`name` varchar(64) DEFAULT NULL COMMENT '名称',
`city_id` int(12) DEFAULT NULL COMMENT '城市',
`sex` tinyint(1) DEFAULT NULL COMMENT '性别',
`phone` varchar(32) DEFAULT NULL COMMENT '电话',
`email` varchar(32) DEFAULT NULL COMMENT '邮箱',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`password` varchar(32) DEFAULT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_user1` (
`id` bigint(20) NOT NULL,
`name` varchar(64) DEFAULT NULL COMMENT '名称',
`city_id` int(12) DEFAULT NULL COMMENT '城市',
`sex` tinyint(1) DEFAULT NULL COMMENT '性别',
`phone` varchar(32) DEFAULT NULL COMMENT '电话',
`email` varchar(32) DEFAULT NULL COMMENT '邮箱',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`password` varchar(32) DEFAULT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
库:
test0,test1
pom:
org.apache.shardingsphere
sharding-jdbc-core
4.1.1
properties:
spring.application.name=shardingjdbc
server.port=8080
datasource0.url=jdbc:mysql://localhost:3306/test0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
datasource0.driver-class-name=com.mysql.cj.jdbc.Driver
datasource0.type=com.alibaba.druid.pool.DruidDataSource
datasource0.username=root
datasource0.password=123456
datasource1.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
datasource1.driver-class-name=com.mysql.cj.jdbc.Driver
datasource1.type=com.alibaba.druid.pool.DruidDataSource
datasource1.username=root
datasource1.password=123456
mybatis.mapper-locations=classpath:com/example/shardingjdbc/mapper/*.xml
mybatis.type-aliases-package=com.example.shardingjdbc.**.entity
#打印sql
spring.shardingsphere.props.sql.show=true
#
spring.datasource.druid.filters=stat,wall,log4j2
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
spring.datasource.druid.web-stat-filter.session-stat-enable=true
spring.datasource.druid.web-stat-filter.session-stat-max-count=1000
#spring.datasource.druid.web-stat-filter.principal-session-name=
#spring.datasource.druid.web-stat-filter.principal-cookie-name=
#spring.datasource.druid.web-stat-filter.profile-enable=
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.reset-enable=false
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=123
spring.datasource.druid.stat-view-servlet.allow=127.0.0.1
spring.datasource.druid.stat-view-servlet.deny=
主键策略:
package com.example.shardingjdbc.config;
import org.apache.shardingsphere.core.strategy.keygen.SnowflakeShardingKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KeyIdConfig {
@Bean("userKeyGenerator")
public SnowflakeShardingKeyGenerator userKeyGenerator() {
return new SnowflakeShardingKeyGenerator();
}
@Bean("orderKeyGenerator")
public SnowflakeShardingKeyGenerator orderKeyGenerator() {
return new SnowflakeShardingKeyGenerator();
}
}
分表分库策略:
package com.example.shardingjdbc.sharding;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import java.util.Collection;
public class UserShardingAlgorithm {
public static final DatabaseShardingAlgorithm databaseShardingAlgorithm = new DatabaseShardingAlgorithm();
public static final TableShardingAlgorithm tableShardingAlgorithm = new TableShardingAlgorithm();
static class DatabaseShardingAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection databaseNames, PreciseShardingValue shardingValue) {
for (String database : databaseNames) {
if (database.endsWith(String.valueOf(shardingValue.getValue() % 2))) {
return database;
}
}
return "";
}
}
static class TableShardingAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection tableNames, PreciseShardingValue shardingValue) {
for (String table : tableNames) {
if (table.endsWith(String.valueOf(shardingValue.getValue() % 2))) {
return table;
}
}
return "";
}
}
}
配置:
1.分表不分库
DataSourceConfig:
package com.example.shardingjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.shardingjdbc.sharding.UserShardingAlgorithm;
import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@Configuration
public class DataSourceConfig {
@Value("${datasource0.url}")
private String url0;
@Value("${datasource0.username}")
private String username0;
@Value("${datasource0.password}")
private String password0;
@Value("${datasource0.driver-class-name}")
private String driverClassName0;
@Value(("${spring.datasource.druid.filters}"))
private String filters;
@Bean("dataSource")
public DataSource dataSource() {
try {
DruidDataSource dataSource0 = new DruidDataSource();
dataSource0.setDriverClassName(this.driverClassName0);
dataSource0.setUrl(this.url0);
dataSource0.setUsername(this.username0);
dataSource0.setPassword(this.password0);
dataSource0.setFilters(this.filters);
//分库设置
Map dataSourceMap = new HashMap<>(2);
//添加数据库database0
dataSourceMap.put("ds0", dataSource0);
// 配置 t_user 表规则
TableRuleConfiguration userRuleConfiguration = new TableRuleConfiguration("t_user", "ds0.t_user${0..1}");
//此处可以自定义
//userRuleConfiguration.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "t_user${id % 2}"));
StandardShardingStrategyConfiguration standardShardingStrategyConfiguration =
new StandardShardingStrategyConfiguration("id", UserShardingAlgorithm.tableShardingAlgorithm);
userRuleConfiguration.setTableShardingStrategyConfig(standardShardingStrategyConfiguration);
//主键
userRuleConfiguration.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "id", getProperties()));
// Sharding全局配置
ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
shardingRuleConfiguration.getTableRuleConfigs().add(userRuleConfiguration);
// 创建数据源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration, new Properties());
return dataSource;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private static Properties getProperties() {
Properties result = new Properties();
result.setProperty("worker.id", "123");
return result;
}
}
2.分库不分表
package com.example.shardingjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.shardingjdbc.sharding.UserShardingAlgorithm;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.*;
@Configuration
public class DataSourceConfig {
@Value("${datasource0.url}")
private String url0;
@Value("${datasource0.username}")
private String username0;
@Value("${datasource0.password}")
private String password0;
@Value("${datasource0.driver-class-name}")
private String driverClassName0;
@Value("${datasource1.url}")
private String url1;
@Value("${datasource1.username}")
private String username1;
@Value("${datasource1.password}")
private String password1;
@Value("${datasource1.driver-class-name}")
private String driverClassName1;
@Value(("${spring.datasource.druid.filters}"))
private String filters;
@Bean("dataSource")
public DataSource dataSource() {
try {
DruidDataSource dataSource0 = new DruidDataSource();
dataSource0.setDriverClassName(this.driverClassName0);
dataSource0.setUrl(this.url0);
dataSource0.setUsername(this.username0);
dataSource0.setPassword(this.password0);
dataSource0.setFilters(this.filters);
DruidDataSource dataSource1 = new DruidDataSource();
dataSource1.setDriverClassName(this.driverClassName1);
dataSource1.setUrl(this.url1);
dataSource1.setUsername(this.username1);
dataSource1.setPassword(this.password1);
dataSource1.setFilters(this.filters);
//分库设置
Map dataSourceMap = new HashMap<>(2);
//添加两个数据库database0和database1
dataSourceMap.put("ds0", dataSource0);
dataSourceMap.put("ds1", dataSource1);
// 配置 t_user 表规则
TableRuleConfiguration userRuleConfiguration = new TableRuleConfiguration("t_user", "ds${0..1}.t_user0");
//id 是 偶数的都插入到了 test0 库的 t_user0 表中, 奇数的都插入到了 test1 库中的 t_user1 表中
/**
* #表策略 行表达式分表规则
* sharding.jdbc.config.sharding.tables.user.actual-data-nodes=ds_$->{0..1}.user_$->{0..4}
* sharding.jdbc.config.sharding.tables.user.table-strategy.inline.sharding-column=id
* sharding.jdbc.config.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 5}
* sharding.jdbc.config.sharding.tables.user.key-generator-column-name=id
*/
// 行表达式分库规则
/**
* #库策略
* sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=id
* harding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{id % 2}
*/
StandardShardingStrategyConfiguration standardShardingStrategyConfiguration =
new StandardShardingStrategyConfiguration("id", UserShardingAlgorithm.databaseShardingAlgorithm);
userRuleConfiguration.setDatabaseShardingStrategyConfig(standardShardingStrategyConfiguration);
// Sharding全局配置
ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
shardingRuleConfiguration.getTableRuleConfigs().add(userRuleConfiguration);
// 创建数据源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration, new Properties());
return dataSource;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
3.分库分表
package com.example.shardingjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.shardingjdbc.sharding.UserShardingAlgorithm;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.*;
@Configuration
public class DataSourceConfig {
@Value("${datasource0.url}")
private String url0;
@Value("${datasource0.username}")
private String username0;
@Value("${datasource0.password}")
private String password0;
@Value("${datasource0.driver-class-name}")
private String driverClassName0;
@Value("${datasource1.url}")
private String url1;
@Value("${datasource1.username}")
private String username1;
@Value("${datasource1.password}")
private String password1;
@Value("${datasource1.driver-class-name}")
private String driverClassName1;
@Value(("${spring.datasource.druid.filters}"))
private String filters;
@Bean("dataSource")
public DataSource dataSource() {
try {
DruidDataSource dataSource0 = new DruidDataSource();
dataSource0.setDriverClassName(this.driverClassName0);
dataSource0.setUrl(this.url0);
dataSource0.setUsername(this.username0);
dataSource0.setPassword(this.password0);
dataSource0.setFilters(this.filters);
DruidDataSource dataSource1 = new DruidDataSource();
dataSource1.setDriverClassName(this.driverClassName1);
dataSource1.setUrl(this.url1);
dataSource1.setUsername(this.username1);
dataSource1.setPassword(this.password1);
dataSource1.setFilters(this.filters);
//分库设置
Map dataSourceMap = new HashMap<>(2);
//添加两个数据库database0和database1
dataSourceMap.put("ds0", dataSource0);
dataSourceMap.put("ds1", dataSource1);
/**
* 除了基本的分库分表规则以外,还有一些其他的配置,比如绑定表。这里先不一一举例了,参照官方文档配即可。
* 举个例子:现在有 order, order_detail两张表,1:1的关系。
* 在配置的时候,应该将相同 order_id 的 order 记录 和 order_detail 记录 映射到相同尾号的表中。这样方便连接查询。比如都插入到 order0, order_detail0中。
* 如果配置了绑定关系,那么只会产生一条查询 select * from order0 as o join order_detail0 as d on o.order_id = d.order_id。
* 否则会产生笛卡儿积查询,
* select * from order0 as o join order_detail0 as d on o.order_id = d.order_id。
* select * from order0 as o join order_detail1 as d on o.order_id = d.order_id。
* select * from order1 as o join order_detail0 as d on o.order_id = d.order_id。
* select * from order1 as o join order_detail1 as d on o.order_id = d.order_id。
*/
// 配置 t_user 表规则 库:test0 test1 表 t_user1 t_user0
TableRuleConfiguration userRuleConfiguration = new TableRuleConfiguration("t_user", "ds${0..1}.t_user${0..1}");
//id 是 偶数的都插入到了 test0 库的 t_user0 表中, 奇数的都插入到了 test1 库中的 t_user1 表中
/**
* #表策略 行表达式分表规则
* sharding.jdbc.config.sharding.tables.user.actual-data-nodes=ds_$->{0..1}.user_$->{0..1}
* sharding.jdbc.config.sharding.tables.user.table-strategy.inline.sharding-column=id
* sharding.jdbc.config.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 5}
* sharding.jdbc.config.sharding.tables.user.key-generator-column-name=id
*/
//sharding.jdbc.config.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name: com.forezp.sharedingjdbcmasterslavetables.MyPreciseShardingAlgorithm
//此处可以自定义
userRuleConfiguration.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "t_user${id % 2}"));
// 行表达式分库规则
/**
* #库策略
* sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=id
* harding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{id % 2}
*/
//根据城市分库
userRuleConfiguration.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("city_id", "ds${city_id % 2}"));
// Sharding全局配置
ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
shardingRuleConfiguration.getTableRuleConfigs().add(userRuleConfiguration);
// 创建数据源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration, new Properties());
return dataSource;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
注意:
1.事务需要手动配置。
2.手动开启sql打印
3.跨节点连接查询问题(分页、排序)
4.多数据源管理问题
分库分表根据业务划分:要注意各表之间的依赖关系,其有个体表,和全局表,全局表可以在每一个库中存放一份,以便提高查询的性能。如:用户表和用户地址表这两张表是相互依赖的,订单明细表和订单表也是相互依赖的,可以存访到一个库中中,减少网路请求I/O。