Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

0%

# 聊聊 Sharding-Jdbc 的简单使用

发表于 2021-12-12 更新于 2022-06-11 分类于 Java 阅读次数： 阅读次数： Disqus：

我们在日常工作中还是使用比较多的分库分表组件的，其中比较优秀的就有 Sharding-Jdbc，一开始由当当开源，后来捐献给了 Apache，说一下简单使用，因为原来经常的使用都是基于 xml 跟 properties 组合起来使用，这里主要试下用 Java Config 来配置
首先是通过 Spring Initializr 创建个带 jdbc 的 Spring Boot 项目，然后引入主要的依赖

    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>shardingsphere-jdbc-core</artifactId>
        <version>5.0.0-beta</version>
    </dependency>

因为前面有聊过 Spring Boot 的自动加载，在这里 spring 就会自己去找 DataSource 的配置，所以要在入口把它干掉

    @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class})
    public class ShardingJdbcDemoApplication implements CommandLineRunner {

然后因为想在入口跑代码，就实现了下 `org.springframework.boot.CommandLineRunner` 主要是后面的 Java Config 代码

    // 注意这里的注解，可以让 Spring 自动帮忙加载，也就是 Java Config 的核心
    @Configuration
    public class MysqlConfig {

        @Bean
        public DataSource dataSource() throws SQLException {
            // Configure actual data sources
            Map<String, DataSource> dataSourceMap = new HashMap<>();

            // Configure the first data source
            // 使用了默认的Hikari连接池的 DataSource
            HikariDataSource dataSource1 = new HikariDataSource();
            dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource1.setJdbcUrl("jdbc:mysql://localhost:3306/sharding");
            dataSource1.setUsername("username");
            dataSource1.setPassword("password");
            dataSourceMap.put("ds0", dataSource1);

            // Configure student table rule
            // 这里是配置分表逻辑，逻辑表是 student，对应真实的表是 student_0 到 student_1, 这个配置方式就是有多少表可以用 student_$->{0..n}
            ShardingTableRuleConfiguration studentTableRuleConfig = new ShardingTableRuleConfiguration("student", "ds0.student_$->{0..1}");

            // 设置分表字段
            studentTableRuleConfig.setTableShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "tableShardingAlgorithm"));

            // Configure sharding rule
            // 配置 studentTableRuleConfig
            ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
            shardingRuleConfig.getTables().add(studentTableRuleConfig);

            // Configure table sharding algorithm
            Properties tableShardingAlgorithmrProps = new Properties();
            // 算法表达式就是根据 user_id 对 2 进行取模
            tableShardingAlgorithmrProps.setProperty("algorithm-expression", "student_${user_id % 2}");
            shardingRuleConfig.getShardingAlgorithms().put("tableShardingAlgorithm", new ShardingSphereAlgorithmConfiguration("INLINE", tableShardingAlgorithmrProps));

            // 然后创建这个 DataSource
            return ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, Collections.singleton(shardingRuleConfig), new Properties());

        }
    }

然后我们就可以在使用这个 DataSource 了，先看下这两个表的数据

    @Override
        public void run(String... args) {
            LOGGER.info("run here");
            String sql = "SELECT * FROM student WHERE user_id=? ";
            try (
                    Connection conn = dataSource.getConnection();
                    PreparedStatement ps = conn.prepareStatement(sql)) {
                // 参数就是 user_id，然后也是分表键，对 2 取模就是 1，应该是去 student_1 取数据
                ps.setInt(1, 1001);

                ResultSet resultSet = ps.executeQuery();
                while (resultSet.next()) {
                    final int id = resultSet.getInt("id");
                    final String name = resultSet.getString("name");
                    final int userId = resultSet.getInt("user_id");
                    final int age = resultSet.getInt("age");
                    System.out.println("奇数表 id：" + id + " 姓名：" + name
                            + " 用户 id：" + userId + " 年龄：" + age );
                    System.out.println("=============================");
                }
                // 参数就是 user_id，然后也是分表键，对 2 取模就是 0，应该是去 student_0 取数据
                ps.setInt(1, 1000);
                resultSet = ps.executeQuery();
                while (resultSet.next()) {
                    final int id = resultSet.getInt("id");
                    final String name = resultSet.getString("name");
                    final int userId = resultSet.getInt("user_id");
                    final int age = resultSet.getInt("age");
                    System.out.println("偶数表 id：" + id + " 姓名：" + name
                            + " 用户 id：" + userId + " 年龄：" + age );
                    System.out.println("=============================");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

看下查询结果