目录
前言:
常见的策略包括:
Java实现哈希分表策略是一种常见的分表策略:
配置分表策略
使用分表
插入数据需要按照分表策略将数据插入到对应的分表:
定义分表Mapper接口
插入数据
哈希算法分表涉及到的代码讲解:
分表查询讲解:
IN分表策略和BETWEEN 条件的分表策略 查询实现:
前言:
水平分表需要考虑数据的一致性和查询效率等问题
常见的策略包括:
-
取模分表策略:根据分表键的值,使用取模运算将数据分散到多个表中。
-
范围分表策略:根据分表键的值,将数据按照一定的范围分散到多个表中,例如按照时间范围、地理位置范围等。
-
哈希分表策略:根据分表键的哈希值,将数据分散到多个表中,可以使用一致性哈希算法等。
-
轮询分表策略:将数据按照一定的顺序分散到多个表中,例如轮询、随机等。
-
按业务分表策略:根据业务需求将数据分散到多个表中,例如按照用户ID、订单ID等。
Java实现哈希分表策略是一种常见的分表策略:
public class HashTableShardingStrategy implements TableShardingStrategy<MyTable> {@Overridepublic String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<MyTable> shardingValue) {// 根据分表键的哈希值,计算出目标表的名称// 例如,可以使用一致性哈希算法将数据分散到多个表中long value = shardingValue.getValue().getId();int index = Math.abs(Long.hashCode(value) % availableTargetNames.size());return "my_table_" + index;}@Overridepublic Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<MyTable> shardingValue) {// 同上,处理IN条件的分表策略return null;}@Overridepublic Collection<String> doBetweenSharding(Collection<String> availableTargetNames, ShardingValue<MyTable> shardingValue) {// 同上,处理BETWEEN条件的分表策略return null;}
}
-
配置分表策略
@Configuration
public class ShardingSphereConfig {@Beanpublic HashTableShardingStrategy hashTableShardingStrategy() {return new HashTableShardingStrategy();}@Beanpublic ShardingRule shardingRule(HashTableShardingStrategy hashTableShardingStrategy) {// 配置分片规则ShardingRule shardingRule = ShardingRule.builder().tableShardingStrategy(new TableShardingStrategyConfiguration("my_table", hashTableShardingStrategy)).build();return shardingRule;}@Beanpublic DataSource dataSource(ShardingRule shardingRule) throws SQLException {// 配置数据源Map<String, DataSource> dataSourceMap = new HashMap<>();dataSourceMap.put("ds0", createDataSource("jdbc:mysql://localhost:3306/db0", "root", "root"));dataSourceMap.put("ds1", createDataSource("jdbc:mysql://localhost:3306/db1", "root", "root"));return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRule, new Properties());}private DataSource createDataSource(String url, String username, String password) {// 创建数据源HikariDataSource dataSource = new HikariDataSource();dataSource.setJdbcUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");return dataSource;}
}
-
使用分表
@Service
public class MyTableServiceImpl implements MyTableService {@Autowiredprivate MyTableMapper myTableMapper;@Overridepublic List<MyTable> listByUserId(long userId) {// 根据分表键查询数据return myTableMapper.selectList(new QueryWrapper<MyTable>().eq("user_id", userId));}
}
插入数据需要按照分表策略将数据插入到对应的分表:
public class MyTable implements Serializable {private Long id;private Long userId;private String name;// 省略getter和setter方法
}
-
定义分表Mapper接口
public interface MyTableMapper extends BaseMapper<MyTable> {
}
-
插入数据
@Service
public class MyTableServiceImpl implements MyTableService {@Autowiredprivate MyTableMapper myTableMapper;@Overridepublic void insert(MyTable myTable) {// 根据分表键计算出目标表的名称String tableName = "my_table_" + Math.abs(Long.hashCode(myTable.getUserId()) % 2);// 设置目标表的名称myTable.setTableName(tableName);// 插入数据myTableMapper.insert(myTable);}
}
插入数据时,需要根据分表键计算出目标表的名称,然后将目标表的名称设置到实体类中,最后插入数据到对应的分表中。
哈希算法分表涉及到的代码讲解:
doEqualSharding
是TableShardingStrategy
接口中的一个方法,用于处理等值查询的分表策略。在使用分表时,查询语句中通常会包含分表键的等值查询条件,例如SELECT * FROM my_table WHERE user_id = 123
,这时就需要根据分表键的值将查询分发到对应的分表中。doEqualSharding
方法的作用就是根据分表键的值,计算出目标表的名称。具体实现可以根据分表键的值,使用取模运算、哈希算法、范围划分等方式将数据分散到多个表中,然后根据分表键的值计算出目标表的名称。Collection<String> availableTargetNames
是分片规则中配置的数据源名称集合,用于指定数据源中的分表名称。在使用分表时,需要将数据分散到多个表中,每个表对应一个数据源。因此,需要在分片规则中配置数据源名称集合createDataSourceMap
方法返回一个包含两个数据源的Map
对象,其中键为数据源名称,值为数据源对象。在分片规则中,使用dataSourceRule
方法将数据源配置到分片规则中,然后在分表策略中使用availableTargetNames
参数获取数据源名称集合,根据分表键的值计算出目标表的名称。例如,在取模分表策略中,可以使用取模运算将数据分散到多个表中,然后根据分表键的值计算出目标表的名称
分表查询讲解:
- 在使用分表时,查询语句中通常会包含分表键的等值查询条件,例如
SELECT * FROM my_table WHERE user_id = 123
,这时就需要根据分表键的值将查询分发到对应的分表中。在 ShardingSphere 中,可以使用分片规则和分表策略来实现数据的分片和查询。 - 在分片规则中,可以配置多个数据源和分表名称集合,然后在分表策略中根据分表键的值计算出目标表的名称,最终将查询分发到对应的数据源和分表中。在查询时,ShardingSphere 会自动将多个数据源中的查询结果合并成一个结果集返回。
- 例如,在以下代码中,
listByUserId
方法根据分表键userId
查询数据,然后将查询结果合并成一个结果集返回:
IN分表策略和BETWEEN
条件的分表策略 查询实现:
在使用分表时,查询语句中可能会包含 IN
条件和 BETWEEN
条件,例如:
SELECT * FROM my_table WHERE user_id IN (1, 2, 3) 2SELECT * FROM my_table WHERE created_at BETWEEN '2022-01-01' AND '2022-01-31'
@Override
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<MyTable> shardingValue) {// 根据分表键的值,计算出目标表的名称集合// 例如,可以使用取模运算将数据分散到多个表中Collection<String> targetNames = new HashSet<>();for (Object value : shardingValue.getValues()) {long id = (long) value;int index = (int) (id % availableTargetNames.size());targetNames.add("my_table_" + index);}return targetNames;
}
doInSharding
方法根据分表键的值,计算出目标表的名称集合。由于IN
条件中可能包含多个值,因此需要遍历所有值,然后根据分表键的值计算出目标表的名称,最终返回目标表的名称集合。
@Override
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames, ShardingValue<MyTable> shardingValue) {// 根据分表键的值,计算出目标表的名称集合// 例如,可以使用取模运算将数据分散到多个表中Collection<String> targetNames = new HashSet<>();Range<Long> range = shardingValue.getValueRange();for (long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {int index = (int) (i % availableTargetNames.size());targetNames.add("my_table_" + index);}return targetNames;
}
doBetweenSharding
方法根据分表键的值,计算出目标表的名称集合。由于BETWEEN
条件中包含一个范围,因此需要遍历范围内的所有值,然后根据分表键的值计算出目标表的名称,最终返回目标表的名称集合。