sharding-JDBC分库分表配置分析
什么是ShardingSphereApache ShardingSphere 由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的基于数据库作为存储节点的增量功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。详细资料点击官网地址.分库分表解决什么问题为什么要分库分表?分库分表就是为了解决由于数
什么是ShardingSphere
Apache ShardingSphere 由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的基于数据库作为存储节点的增量功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。
详细资料点击官网地址.
分库分表解决什么问题
- 为什么要分库分表?
- 分库分表就是为了解决由于数据量(比如电商的订单)过大而导致数据库性能(CPU、内存、磁盘、网络)降低的问题,将原本单个数据库拆分成多个数据库 ,将数据量大的表拆分成若干个数据表,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。
- 分库分表的四种方式:垂直分库、垂直分表、水平分库和水平分表
- 垂直分库:
- 通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,大大提高性能。但是依然没有解决单表数据量过大的问题,且需要解决跨库带来的复杂性问题。
- 垂直分表:
- 把一个字段比较多的表按照字段访问频次冷热程度、是否是大字段的原则拆分为多个表,这样既能使业务清晰,还能提升部分性能。拆分后,尽量从业务角度避免联查,否则性能方面将得不偿失。
- 水平分库:
- 把一张表的数据(数据行)按一定规则拆分到不同的数据库中,每个库只有这个表的部分数据,这些数据库可以分布在不同的服务器上,从而使访问压力被多服务器负载,提升性能。它不仅需要解决跨库带来的问题,还需要解决数据路由的问题。
- 水平分表:
- 把一张表的数据(数据行)分到多个同一个数据库的多张表中,每个表只有这个表的部分数据,解决单表数据量过大而产生的性能问题,它仅仅作为水平分库的一个补充优化。
数据库相关优化方案
- 软件层面包括:SQL调优、表结构优化、读写分离、数据库集群、分库分表等。
- 硬件层面主要是增加机器性能。
两种情况下:
- 当数据量随着业务量的提升不断增大,但访问数据库压力不是特别大的情况下,我们首先考虑缓存、读写分离、索引等技术方案。
- 当数据量特别大并且持续增长时,即将或者已经出现性能瓶颈时,可以考虑分库分表方案。
Springboot整合Sharding-JDBC
ShardingJDBC简介
定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
- 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
- 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等。
- 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。
Sharding-JDBC核心配置
- 分片规则
- 分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等
- 数据源配置
- 真实数据源列表
- 表配置
- 逻辑表名称、数据节点与分表规则的配置
- 数据节点配置
- 用于配置逻辑表与真实表的映射关系。可分为均匀分布和自定义分布两种形式
- 分片策略配置
对于分片策略存有数据源分片策略和表分片策略两种维度
- 数据源分片策略
- 对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源
- 表分片策略
- 对应于TableShardingStrategy。用于配置数据被分配的目标表,该目标表存在与该数据的目标数据源内。故表分片策略是依赖与数据源分片策略的结果的
- 自增主键生成策略
- 通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。
SpringBoot整合Sharding-JDBC实现代码
在这里我们主要基于JavaConfig配置的方式来集成到SpringBoot中,代码如下:
1、pom文件中添加Sharding-JDBC和MySQL驱动依赖,以及其他的相关依赖,我这里使用的是阿里巴巴Druid数据库连接池。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>${spring-boot.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${joda.time.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <scope>compile</scope> <exclusions> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> <version>4.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> </dependencies>
2、配置数据源(两个数据库)
spring: shardingsphere: datasource: # 数据源:shard_one dataOne: type: com.alibaba.druid.pool.DruidDataSource druid: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/shard_one?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false username: root password: 123456 initial-size: 10 max-active: 100 min-idle: 10 max-wait: 60000 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 max-evictable-idle-time-millis: 60000 validation-query: SELECT 1 FROM DUAL # validation-query-timeout: 5000 test-on-borrow: false test-on-return: false test-while-idle: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 数据源:shard_two dataTwo: type: com.alibaba.druid.pool.DruidDataSource druid: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/shard_two?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false username: root password: 123456 initial-size: 10 max-active: 100 min-idle: 10 max-wait: 60000 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 max-evictable-idle-time-millis: 60000 validation-query: SELECT 1 FROM DUAL # validation-query-timeout: 5000 test-on-borrow: false test-on-return: false test-while-idle: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
3、创建两个数据库dataOne的实例
public class TableOne { private Long id; private String phone; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } private String sex; }
4、创建TableOne数据访问接口
public interface TableOneService { void createTable () ; void insertOne () ; List<TableOne> selectOneByPhone (String phone) ; }
5、创建TableOne数据访问实现类
@Service public class TableOneServiceImpl implements TableOneService { @Resource private TableOneMapper tableOneMapper ; @Autowired @Qualifier("dataOneTemplate") private JdbcTemplate dataOneTemplate ; @Autowired @Qualifier("dataTwoTemplate") private JdbcTemplate dataTwoTemplate ; @Override public void createTable() { for (int i = 1 ; i <= 5 ; i++){ String executeSQL = "CREATE TABLE table_one_"+i+" (\n" + " `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n" + " `phone` varchar(20) NOT NULL COMMENT '手机号',\n" + " `name` varchar(50) DEFAULT NULL COMMENT '备用1',\n" + " `sex` varchar(50) DEFAULT NULL COMMENT '备用2',\n" + " PRIMARY KEY (`id`),\n" + " KEY `phoneIndex` (`phone`)\n" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8;" ; dataOneTemplate.execute(executeSQL); dataTwoTemplate.execute(executeSQL); } } @Override public void insertOne() { for (int i = 0 ; i < 20 ; i++){ Long id = new SnowFlake(5,6).nextId(false); TableOne tableOne = new TableOne() ; tableOne.setId(id); tableOne.setPhone("188136777"+i); tableOne.setName("张三"+i); tableOne.setSex("男"); tableOneMapper.insert(tableOne) ; } } @Override public List<TableOne> selectOneByPhone(String phone) { return tableOneMapper.selectOneByPhone(phone); } }
6、创建Mapper接口以及实现SQL操作
@Mapper public interface TableOneMapper { List<TableOne> selectOneByPhone (@Param("phone") String phone) ; int insert(TableOne record); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.shard.jdbc.mapper.TableOneMapper" > <resultMap id="BaseResultMap" type="com.shard.jdbc.entity.TableOne" > <id column="id" property="id"/> <result column="phone" property="phone"/> <result column="name" property="name"/> <result column="sex" property="sex"/> </resultMap> <sql id="Base_Column_List" > id, phone, name, sex </sql> <select id="selectOneByPhone" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from table_one where phone = #{phone} </select> <insert id="insert" parameterType="com.shard.jdbc.entity.TableOne" useGeneratedKeys="true" keyProperty="id" > insert into table_one (id,phone, name, sex) values (#{phone,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{sex,jdbcType=VARCHAR}) </insert> </mapper>
7、数据库分库分表配置()
7.1 连接数据源/** * shard_one数据源 */ @Value("${spring.datasource.dataOne.druid.url}") private String dbUrl1; @Value("${spring.datasource.dataOne.druid.username}") private String username1; @Value("${spring.datasource.dataOne.druid.password}") private String password1; @Value("${spring.datasource.dataOne.druid.driverClassName}") private String driverClassName1; @Value("${spring.datasource.dataOne.druid.initial-size}") private int initialSize1; @Value("${spring.datasource.dataOne.druid.max-active}") private int maxActive1; @Value("${spring.datasource.dataOne.druid.min-idle}") private int minIdle1; @Value("${spring.datasource.dataOne.druid.max-wait}") private int maxWait1; @Value("${spring.datasource.dataOne.druid.pool-prepared-statements}") private boolean poolPreparedStatements1; @Value("${spring.datasource.dataOne.druid.max-pool-prepared-statement-per-connection-size}") private int maxPoolPreparedStatementPerConnectionSize1; @Value("${spring.datasource.dataOne.druid.time-between-eviction-runs-millis}") private int timeBetweenEvictionRunsMillis1; @Value("${spring.datasource.dataOne.druid.min-evictable-idle-time-millis}") private int minEvictableIdleTimeMillis1; @Value("${spring.datasource.dataOne.druid.max-evictable-idle-time-millis}") private int maxEvictableIdleTimeMillis1; @Value("${spring.datasource.dataOne.druid.validation-query}") private String validationQuery1; @Value("${spring.datasource.dataOne.druid.test-while-idle}") private boolean testWhileIdle1; @Value("${spring.datasource.dataOne.druid.test-on-borrow}") private boolean testOnBorrow1; @Value("${spring.datasource.dataOne.druid.test-on-return}") private boolean testOnReturn1; @Value("{spring.datasource.dataOne.druid.connection-properties}") private String connectionProperties1; @Bean public DruidDataSource dataOneSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(dbUrl1); datasource.setUsername(username1); datasource.setPassword(password1); datasource.setDriverClassName(driverClassName1); datasource.setInitialSize(initialSize1); datasource.setMinIdle(minIdle1); datasource.setMaxActive(maxActive1); datasource.setMaxWait(maxWait1); datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis1); datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis1); datasource.setMaxEvictableIdleTimeMillis(minEvictableIdleTimeMillis1); datasource.setValidationQuery(validationQuery1); datasource.setTestWhileIdle(testWhileIdle1); datasource.setTestOnBorrow(testOnBorrow1); datasource.setTestOnReturn(testOnReturn1); datasource.setPoolPreparedStatements(poolPreparedStatements1); datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize1); datasource.setConnectionProperties(connectionProperties1); return datasource; } /** * shard_two数据源 */ @Value("${spring.datasource.dataTwo.druid.url}") private String dbUrl2; @Value("${spring.datasource.dataTwo.druid.username}") private String username2; @Value("${spring.datasource.dataTwo.druid.password}") private String password2; @Value("${spring.datasource.dataTwo.druid.driverClassName}") private String driverClassName2; @Value("${spring.datasource.dataTwo.druid.initial-size}") private int initialSize2; @Value("${spring.datasource.dataTwo.druid.max-active}") private int maxActive2; @Value("${spring.datasource.dataTwo.druid.min-idle}") private int minIdle2; @Value("${spring.datasource.dataTwo.druid.max-wait}") private int maxWait2; @Value("${spring.datasource.dataTwo.druid.pool-prepared-statements}") private boolean poolPreparedStatements2; @Value("${spring.datasource.dataTwo.druid.max-pool-prepared-statement-per-connection-size}") private int maxPoolPreparedStatementPerConnectionSize2; @Value("${spring.datasource.dataTwo.druid.time-between-eviction-runs-millis}") private int timeBetweenEvictionRunsMillis2; @Value("${spring.datasource.dataTwo.druid.min-evictable-idle-time-millis}") private int minEvictableIdleTimeMillis2; @Value("${spring.datasource.dataTwo.druid.max-evictable-idle-time-millis}") private int maxEvictableIdleTimeMillis2; @Value("${spring.datasource.dataTwo.druid.validation-query}") private String validationQuery2; @Value("${spring.datasource.dataTwo.druid.test-while-idle}") private boolean testWhileIdle2; @Value("${spring.datasource.dataTwo.druid.test-on-borrow}") private boolean testOnBorrow2; @Value("${spring.datasource.dataTwo.druid.test-on-return}") private boolean testOnReturn2; @Value("{spring.datasource.dataTwo.druid.connection-properties}") private String connectionProperties2; @Bean public DruidDataSource dataTwoSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(dbUrl2); datasource.setUsername(username2); datasource.setPassword(password2); datasource.setDriverClassName(driverClassName2); datasource.setInitialSize(initialSize2); datasource.setMinIdle(minIdle2); datasource.setMaxActive(maxActive2); datasource.setMaxWait(maxWait2); datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis2); datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis2); datasource.setMaxEvictableIdleTimeMillis(minEvictableIdleTimeMillis2); datasource.setValidationQuery(validationQuery2); datasource.setTestWhileIdle(testWhileIdle2); datasource.setTestOnBorrow(testOnBorrow2); datasource.setTestOnReturn(testOnReturn2); datasource.setPoolPreparedStatements(poolPreparedStatements2); datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize2); datasource.setConnectionProperties(connectionProperties2); return datasource; }
7.2 JDBC操作配置(这里主要用于自定义创建表,controller层中)
@Bean(name = "dataOneTemplate") public JdbcTemplate dataOneTemplate (@Autowired DruidDataSource dataOneSource){ return new JdbcTemplate(dataOneSource) ; } @Bean(name = "dataTwoTemplate") public JdbcTemplate dataTwoTemplate (@Autowired DruidDataSource dataTwoSource){ return new JdbcTemplate(dataTwoSource) ; }
如下图:
7.3 Shard-JDBC 分库分表配置@Bean public DataSource dataSource (@Autowired DruidDataSource dataOneSource, @Autowired DruidDataSource dataTwoSource) throws Exception { ShardingRuleConfiguration shardJdbcConfig = new ShardingRuleConfiguration(); // 配置分库分表规则 shardJdbcConfig.getTableRuleConfigs().add(getTableRule01()); shardJdbcConfig.getTableRuleConfigs().add(getTableRule02()); //配置默认数据源 shardJdbcConfig.setDefaultDataSourceName("ds_0"); //绑定表的关联 shardJdbcConfig.getBindingTableGroups().add("table_one,table_two"); //2配置读写分离规则 /*shardingRuleConfig.setMasterSlaveRuleConfigs();*/ //指定需要分库分表的数据源 Map<String,DataSource> dataMap = new LinkedHashMap<>() ; dataMap.put("ds_0",dataOneSource) ; dataMap.put("ds_1",dataTwoSource) ; //属性配置项,可以为以下属性 Properties prop = new Properties(); //是否打印SQL解析和改写日志 prop.setProperty("sql.show",Boolean.TRUE.toString()); //用于SQL执行的工作线程数量,为零则表示无限制 prop.setProperty("executor.size","4"); //每个物理数据库为每次查询分配的最大连接数量 prop.setProperty("max.connections.size.per.query","1"); //是否在启动时检查分表元数据一致性 prop.setProperty("check.table.metadata.enabled","false"); return ShardingDataSourceFactory.createDataSource(dataMap, shardJdbcConfig,prop); }
这里需要注意一点是表的绑定:
//绑定表的关联
shardJdbcConfig.getBindingTableGroups().add(“table_one,table_two”);指分片规则一致的主表和子表。 例如:t_order 表和 t_order_item 表,均按照 order_id 分片,则此两张表互为绑定表关系。 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。 举例说明,如果 SQL 为:
SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在不配置绑定表关系时,假设分片键 order_id 将数值 10 路由至第 0 片,将数值 11 路由至第 1 片,那么路由后的 SQL 应该为 4 条,它们呈现为笛卡尔积:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在配置绑定表关系后,路由的 SQL 应该为 2 条:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
其中 t_order 在 FROM 的最左侧,ShardingSphere 将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么 t_order_item 表的分片计算将会使用 t_order 的条件。 因此,绑定表间的分区键需要完全相同。
7.4 Shard-JDBC 分表配置
private static TableRuleConfiguration getTableRule01() { // param1 : 逻辑表名, param2 : 真实存在的节点,由数据源 + 表名组成, ds${0..1} 代表 数据库选择 ds 后缀为 0 - 1 之间,table_one 代表数据表 table_one 后缀 1 - 5 之间 TableRuleConfiguration result = new TableRuleConfiguration("table_one","ds_${0..1}.table_one_${1..5}"); //主键生成列,默认的主键生成算法是snowflake result.setKeyGeneratorConfig(getKeyGeneratorConfiguration()); // 设置数据源分片规则 //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则 result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new DataSourceAlg())); // 设置数据表分片规则 //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则 result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new TableOneAlg())); return result; } private static TableRuleConfiguration getTableRule02() { // param1 : 逻辑表名, param2 : 真实存在的节点,由数据源 + 表名组成, ds${0..1} 代表 数据库选择 ds 后缀为 0 - 1 之间,table_two 代表数据表 table_two 后缀 1 - 5 之间 TableRuleConfiguration result = new TableRuleConfiguration("table_two","ds_${0..1}.table_two_${1..5}"); //主键生成列,默认的主键生成算法是snowflake result.setKeyGeneratorConfig(getKeyGeneratorConfiguration()); // 设置数据源分片规则 //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则 result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new DataSourceAlg())); // 设置数据表分片规则 //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则 result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new TableTwoAlg())); return result; }
- getTableRule01和getTableRule02方法都是指定数据库的逻辑表和真实表以及数据写入指定数据库当中
- 配置数据库分片策略
result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration(“phone”, new DataSourceAlg()));
public class DataSourceAlg implements PreciseShardingAlgorithm<String> { private static Logger LOG = LoggerFactory.getLogger(DataSourceAlg.class); @Override public String doSharding(Collection<String> names, PreciseShardingValue<String> value) { LOG.debug("分库算法参数 {},{}",names,value); int hash = HashUtil.rsHash(String.valueOf(value.getValue())); return "ds_" + ((hash % 2)) ; } }
分片采用行表达式分片策略,代码中分片主键为phone,根据phone的hash计算分配到不同的数据库中,规则为:根据phone和2取模,将数据分别存入数据库shard_one和shard_two当中。
- 配置表分片策略
result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration(“phone”, new TableTwoAlg()));
public class TableTwoAlg implements PreciseShardingAlgorithm<String> { private static Logger LOG = LoggerFactory.getLogger(TableTwoAlg.class); @Override public String doSharding(Collection<String> names, PreciseShardingValue<String> value) { LOG.info("参数:{},{}",names,value); int hash = HashUtil.rsHash(String.valueOf(value.getValue())); LOG.info("数据存入的表table_two_{}",(hash % 5+1)); return "table_two_" + (hash % 5+1); } }
这里以table_two表说明(table_one规则一样),
分表以phone为分片键进行分表,分片算法为PreciseShardingAlgorithm.
collection中存的表名table_two_1…table_two_5,根据 int hash = HashUtil.rsHash(String.valueOf(value.getValue()));计算得到的值决定将当前数据存入哪个表中,
执行sql语句如下:7.5 主键生成列(雪花算法)
public static KeyGeneratorConfiguration getKeyGeneratorConfiguration(){ KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE","id"); return result; }
更多推荐
所有评论(0)