目录
前言:
常见的策略包括:
Java实现哈希分表策略是一种常见的分表策略:
配置分表策略
使用分表
插入数据需要按照分表策略将数据插入到对应的分表:
定义分表Mapper接口
插入数据
哈希算法分表涉及到的代码讲解:
分表查询讲解:
IN分表策略和BETWEEN 条件的分表策略 查询实现:
水平分表需要考虑数据的一致性和查询效率等问题
取模分表策略:根据分表键的值,使用取模运算将数据分散到多个表中。
范围分表策略:根据分表键的值,将数据按照一定的范围分散到多个表中,例如按照时间范围、地理位置范围等。
哈希分表策略:根据分表键的哈希值,将数据分散到多个表中,可以使用一致性哈希算法等。
轮询分表策略:将数据按照一定的顺序分散到多个表中,例如轮询、随机等。
按业务分表策略:根据业务需求将数据分散到多个表中,例如按照用户ID、订单ID等。
public class HashTableShardingStrategy implements TableShardingStrategy {
@Override
public String doEqualSharding(Collection availableTargetNames, ShardingValue shardingValue) {
// 根据分表键的哈希值,计算出目标表的名称
// 例如,可以使用一致性哈希算法将数据分散到多个表中
long value = shardingValue.getValue().getId();
int index = Math.abs(Long.hashCode(value) % availableTargetNames.size());
return "my_table_" + index;
}
@Override
public Collection doInSharding(Collection availableTargetNames, ShardingValue shardingValue) {
// 同上,处理IN条件的分表策略
return null;
}
@Override
public Collection doBetweenSharding(Collection availableTargetNames, ShardingValue shardingValue) {
// 同上,处理BETWEEN条件的分表策略
return null;
}
}
@Configuration
public class ShardingSphereConfig {
@Bean
public HashTableShardingStrategy hashTableShardingStrategy() {
return new HashTableShardingStrategy();
}
@Bean
public ShardingRule shardingRule(HashTableShardingStrategy hashTableShardingStrategy) {
// 配置分片规则
ShardingRule shardingRule = ShardingRule.builder()
.tableShardingStrategy(new TableShardingStrategyConfiguration("my_table", hashTableShardingStrategy))
.build();
return shardingRule;
}
@Bean
public DataSource dataSource(ShardingRule shardingRule) throws SQLException {
// 配置数据源
Map 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 {
@Autowired
private MyTableMapper myTableMapper;
@Override
public List listByUserId(long userId) {
// 根据分表键查询数据
return myTableMapper.selectList(new QueryWrapper().eq("user_id", userId));
}
}
public class MyTable implements Serializable {
private Long id;
private Long userId;
private String name;
// 省略getter和setter方法
}
public interface MyTableMapper extends BaseMapper {
}
@Service
public class MyTableServiceImpl implements MyTableService {
@Autowired
private MyTableMapper myTableMapper;
@Override
public 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 availableTargetNames
是分片规则中配置的数据源名称集合,用于指定数据源中的分表名称。在使用分表时,需要将数据分散到多个表中,每个表对应一个数据源。因此,需要在分片规则中配置数据源名称集合createDataSourceMap
方法返回一个包含两个数据源的 Map
对象,其中键为数据源名称,值为数据源对象。在分片规则中,使用 dataSourceRule
方法将数据源配置到分片规则中,然后在分表策略中使用 availableTargetNames
参数获取数据源名称集合,根据分表键的值计算出目标表的名称。例如,在取模分表策略中,可以使用取模运算将数据分散到多个表中,然后根据分表键的值计算出目标表的名称SELECT * FROM my_table WHERE user_id = 123
,这时就需要根据分表键的值将查询分发到对应的分表中。在 ShardingSphere 中,可以使用分片规则和分表策略来实现数据的分片和查询。listByUserId
方法根据分表键 userId
查询数据,然后将查询结果合并成一个结果集返回: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 doInSharding(Collection availableTargetNames, ShardingValue shardingValue) {
// 根据分表键的值,计算出目标表的名称集合
// 例如,可以使用取模运算将数据分散到多个表中
Collection 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 doBetweenSharding(Collection availableTargetNames, ShardingValue shardingValue) {
// 根据分表键的值,计算出目标表的名称集合
// 例如,可以使用取模运算将数据分散到多个表中
Collection targetNames = new HashSet<>();
Range 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
条件中包含一个范围,因此需要遍历范围内的所有值,然后根据分表键的值计算出目标表的名称,最终返回目标表的名称集合。