[Java 实现水平分表 2]

目录

前言:

常见的策略包括:

Java实现哈希分表策略是一种常见的分表策略:

配置分表策略

使用分表

插入数据需要按照分表策略将数据插入到对应的分表:

定义分表Mapper接口

插入数据

哈希算法分表涉及到的代码讲解:

分表查询讲解:

IN分表策略和BETWEEN 条件的分表策略 查询实现:


前言:

   水平分表需要考虑数据的一致性和查询效率等问题

常见的策略包括:

  • 取模分表策略:根据分表键的值,使用取模运算将数据分散到多个表中。

  • 范围分表策略:根据分表键的值,将数据按照一定的范围分散到多个表中,例如按照时间范围、地理位置范围等。

  • 哈希分表策略:根据分表键的哈希值,将数据分散到多个表中,可以使用一致性哈希算法等。

  • 轮询分表策略:将数据按照一定的顺序分散到多个表中,例如轮询、随机等。

  • 按业务分表策略:根据业务需求将数据分散到多个表中,例如按照用户ID、订单ID等。

Java实现哈希分表策略是一种常见的分表策略:

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;
    }
}
  1. 配置分表策略

@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;
    }
}
  1. 使用分表

@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方法
}
  1. 定义分表Mapper接口

public interface MyTableMapper extends BaseMapper {
}
  1. 插入数据

@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 中,可以使用分片规则和分表策略来实现数据的分片和查询。
  • 在分片规则中,可以配置多个数据源和分表名称集合,然后在分表策略中根据分表键的值计算出目标表的名称,最终将查询分发到对应的数据源和分表中。在查询时,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 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 条件中包含一个范围,因此需要遍历范围内的所有值,然后根据分表键的值计算出目标表的名称,最终返回目标表的名称集合。

你可能感兴趣的:(粉丝栏,java,开发语言)