美文网首页我爱编程
sharding-sphere学习(1)之-[raw-examp

sharding-sphere学习(1)之-[raw-examp

作者: 码农进化史 | 来源:发表于2018-05-27 19:42 被阅读0次

    发现梦想与现实的差距后,坚持就越来越远

    前段时间在刷博客的时候,无意间刷到了一篇介绍数据库分库分表的框架,于是网上搜了一下,shardingjdbc 当当团队网团队开源的一个专做对于java开发在原生的jdbc层上封装的一层轻量级中间件。我们看一下它的官网(http://shardingjdbc.io/index_zh.html)给的介绍:

    sharding-sphere

    对于shardingjdbc来说无非就是通过java代码在原生的jdbc上封装了一层,如果说自己去研发一个这样的中间件也不是不可能。就是后期考虑到出现的bug、效率、性能等问题,没有一个更好的前期规划也很难完成。定位上面这个轻量级的框架通过上面给的架构图来说,无非就是在jdbc层进行更好的封装集成,从而形成一个加强版的JDBC连接数据库的工具。没有任何侵入性,完全可以兼容任何的ORM框架,这一点确实是可以值得一用的。


    sharding-jdbc

    下面我们来看看sharding-jdbc为我们提供的功能有哪些?官网也有具体的介绍:

    • 数据分片
      数据分片主要以分库+分表的操作、支持的sql语句查询方式以及分布式主键的处理方案等
    • 读写分离
      读写分离主要以一主多从、统一线程数据的一致性以及分库分表时的读写分离操作等
    • 事物处理
      主要针对TCC分布式事物处理解决
    • 分布式治理
      主要一些熔断措施,以及配置中心的配置。

    基本的说明就这些,后续将会沿着例子区找到源码进行进一步的研究和探讨。接下来可以去github上将shardingjdbc-example(https://github.com/sharding-sphere/sharding-sphere-example)例子下载下来运行,如下图,由于版本原因选择branches版本下载:

    分支
    本机运行例子需要选择master版本的,dev是开发版本,暂时maven代码库还没有更新上去。
    master
    可以直接下载zip也可以直接使用:
    git clone https://github.com/sharding-sphere/sharding-sphere-example.git
    

    直接下载下来。然后将下载下来的项目导入到IDEA中如下图:

    example运行例子

    注意:当前我使用的sharding-jdbc版本是2.0.3。git可能会是最新版本。应该都可以用的运行的,只是目录有点不一样了。

    我们来看看官网给的例子,首先在每个项目模块下面对java实现的每个ORM框架进行了组个demo演示,无论我们使用哪种框架,只需要导入所需的jar包便可以完美的和ORM框架结合。
    首先我们先来看看在与原生的jdbc结合的时候sharding-jdbc是怎么实现分库分表的策略的。找到

    sharding-jdbc-raw-jdbc-example
    
    sharding-jdbc-raw-jdbc-example

    该模块下的

    sharding-jdbc-raw-jdbc-java-example // 原生代码与sharding-jdbc结合
    
    /**仅读写分离操作*/
    RawJdbcJavaMasterSlaveOnlyMain
    /**读写分离+分库分表操作*/
    RawJdbcJavaShardingAndMasterSlaveMain
    /**分库分表操作*/
    RawJdbcJavaShardingDatabaseAndTableMain
    /**仅分库操作*/
    RawJdbcJavaShardingDatabaseOnlyMain
    /**仅做分表操作*/
    RawJdbcJavaShardingTableOnlyMain
    

    注意:在运行demo前请先将基本的数据库先初始化好,在每个模块的根目录下会有一个sql文件,是根据自己的业务来制定的建库规则来创建对应的库:


    需要执行的建库sql

    在创建好数据库后将会有12个对应的数据库,待后续example会使用到:


    初始化example的数据库

    下面将从分库模块学习使用入口:

    /**仅分库操作*/
    RawJdbcJavaShardingDatabaseOnlyMain
    

    使用到的库:

    • demo_ds_0
    • demo_ds_1
      运行该example结果如下:
    1.动态创建表成功--------------
    2.插入数据成功--------------
    3.打印 Equals 查询结果--------------
    order_item_id:1, order_id:207575701002387456, user_id:10
    order_item_id:2, order_id:207575701472149504, user_id:10
    order_item_id:3, order_id:207575701568618496, user_id:10
    order_item_id:4, order_id:207575701669281792, user_id:10
    order_item_id:5, order_id:207575701803499520, user_id:10
    order_item_id:6, order_id:207575701950300160, user_id:10
    order_item_id:7, order_id:207575702038380544, user_id:10
    order_item_id:8, order_id:207575702118072320, user_id:10
    order_item_id:9, order_id:207575702256484352, user_id:10
    4.打印使用 In 查询结果--------------
    order_item_id:1, order_id:207575701405040640, user_id:11
    order_item_id:2, order_id:207575701518286848, user_id:11
    order_item_id:3, order_id:207575701623144448, user_id:11
    order_item_id:4, order_id:207575701723807744, user_id:11
    order_item_id:5, order_id:207575701899968512, user_id:11
    order_item_id:6, order_id:207575701988048896, user_id:11
    order_item_id:7, order_id:207575702080323584, user_id:11
    order_item_id:8, order_id:207575702218735616, user_id:11
    order_item_id:9, order_id:207575702290038784, user_id:11
    order_item_id:1, order_id:207575701002387456, user_id:10
    order_item_id:2, order_id:207575701472149504, user_id:10
    order_item_id:3, order_id:207575701568618496, user_id:10
    order_item_id:4, order_id:207575701669281792, user_id:10
    order_item_id:5, order_id:207575701803499520, user_id:10
    order_item_id:6, order_id:207575701950300160, user_id:10
    order_item_id:7, order_id:207575702038380544, user_id:10
    order_item_id:8, order_id:207575702118072320, user_id:10
    order_item_id:9, order_id:207575702256484352, user_id:10
    4.打印使用 Hint 查询结果--------------
    order_item_id:1, order_id:207575701405040640, user_id:11
    order_item_id:2, order_id:207575701518286848, user_id:11
    order_item_id:3, order_id:207575701623144448, user_id:11
    order_item_id:4, order_id:207575701723807744, user_id:11
    order_item_id:5, order_id:207575701899968512, user_id:11
    order_item_id:6, order_id:207575701988048896, user_id:11
    order_item_id:7, order_id:207575702080323584, user_id:11
    order_item_id:8, order_id:207575702218735616, user_id:11
    order_item_id:9, order_id:207575702290038784, user_id:11
    

    数据库中的表如图所示:


    分库插入数据

    基本执行步骤如下:

        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:15
         * @Description: 配置数据源
         */
        private static DataSource getShardingDataSource() throws SQLException {
            /**初始化sharding配置*/
            ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
            /**添加创建主订单表*/
            shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
            /**添加创建订单项表*/
            shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());
            /**根据主订单表中的user_id字段定位该笔订单入库规则,这里使用user_id的奇偶数来定位插库入口*/
            shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "demo_ds_${user_id % 2}"));
            /**创建好数据源并加入配置中得到数据源配置*/
            return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new HashMap<String, Object>(), new Properties());
        }
    
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:20
         * @Description: 主订单表规则的基本配置
         */
        private static TableRuleConfiguration getOrderTableRuleConfiguration() {
            TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
            orderTableRuleConfig.setLogicTable("t_order");
            /**设置主键*/
            orderTableRuleConfig.setKeyGeneratorColumnName("order_id");
            return orderTableRuleConfig;
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:22 
         * @Description: 订单项目表的配置规则
         */
        private static TableRuleConfiguration getOrderItemTableRuleConfiguration() {
            TableRuleConfiguration orderItemTableRuleConfig = new TableRuleConfiguration();
            orderItemTableRuleConfig.setLogicTable("t_order_item");
            return orderItemTableRuleConfig;
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:22 
         * @Description: 创建两个动态数据源 demo_ds_0 、 demo_ds_1
         */
        private static Map<String, DataSource> createDataSourceMap() {
            Map<String, DataSource> result = new HashMap<>(2, 1);
            result.put("demo_ds_0", DataSourceUtil.createDataSource("demo_ds_0"));
            result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1"));
            return result;
        }
    

    执行的具体操作类关键实现如下:

        private final DataSource dataSource;
        
        /**初始化数据源*/
        public RawJdbcRepository(final DataSource dataSource) {
            this.dataSource = dataSource;
        }
        
        public void demo() throws SQLException {
            /**创建表*/
            System.out.println("1.动态创建表--------------");
            this.createTable();
            /**插入数据*/
            System.out.println("2.插入数据--------------");
            this.insertData();
            /**打印查询*/
            System.out.println("3.打印 Equals 查询结果--------------");
            printEqualsSelect();
            System.out.println("4.打印使用 In 查询结果--------------");
            printInSelect();
            System.out.println("4.打印使用 Hint 查询结果--------------");
            printHintSimpleSelect();
    //        dropTable();
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:24 
         * @Description: 动态创建表
         */
        public void createTable() throws SQLException {
            execute(dataSource, "CREATE TABLE IF NOT EXISTS t_order (order_id BIGINT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id))");
            execute(dataSource, "CREATE TABLE IF NOT EXISTS t_order_item (order_item_id BIGINT NOT NULL AUTO_INCREMENT, order_id BIGINT NOT NULL, user_id INT NOT NULL, PRIMARY KEY (order_item_id))");
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:25 
         * @Description: 删除表
         */
        public void dropTable() throws SQLException {
            execute(dataSource, "DROP TABLE t_order_item");
            execute(dataSource, "DROP TABLE t_order");
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:25 
         * @Description: 插入数据
         */
        public void insertData() throws SQLException {
            for (int i = 1; i < 10; i++) {
                long orderId = this.executeAndGetGeneratedKey(dataSource, "INSERT INTO t_order (user_id, status) VALUES (10, 'INIT')");
                this.execute(dataSource, String.format("INSERT INTO t_order_item (order_id, user_id) VALUES (%d, 10)", orderId));
                orderId = this.executeAndGetGeneratedKey(dataSource, "INSERT INTO t_order (user_id, status) VALUES (11, 'INIT')");
                this.execute(dataSource, String.format("INSERT INTO t_order_item (order_id, user_id) VALUES (%d, 11)", orderId));
            }
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:25 
         * @Description: 使用 Equals 查询数据
         */
        public void printEqualsSelect() throws SQLException {
            String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=?";
            try (
                    Connection conn = dataSource.getConnection();
                    PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
                preparedStatement.setInt(1, 10);
                printSimpleSelect(preparedStatement);
            }
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:26 
         * @Description: 使用 In 查询数据
         */
        public void printInSelect() throws SQLException {
            String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id IN (?, ?)";
            try (
                    Connection conn = dataSource.getConnection();
                    PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
                preparedStatement.setInt(1, 10);
                preparedStatement.setInt(2, 11);
                printSimpleSelect(preparedStatement);
            }
        }
    
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:27 
         * @Description: 使用 Hint 查询数据
         */
        public void printHintSimpleSelect() throws SQLException {
            String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id";
            try (
                    HintManager hintManager = HintManager.getInstance();
                    Connection conn = dataSource.getConnection();
                    PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
                hintManager.addDatabaseShardingValue("t_order", "user_id", 11);
                printSimpleSelect(preparedStatement);
            }
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:27 
         * @Description: 打印并遍历查询结果
         */
        private void printSimpleSelect(final PreparedStatement preparedStatement) throws SQLException {
            try (ResultSet rs = preparedStatement.executeQuery()) {
                while (rs.next()) {
                    System.out.print("order_item_id:" + rs.getLong(1) + ", ");
                    System.out.print("order_id:" + rs.getLong(2) + ", ");
                    System.out.print("user_id:" + rs.getInt(3));
                    System.out.println();
                }
            }
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:27 
         * @Description: 执行连接数据源
         */
        private void execute(final DataSource dataSource, final String sql) throws SQLException {
            try (
                    Connection conn = dataSource.getConnection();
                    Statement statement = conn.createStatement()) {
                statement.execute(sql);
            }
        }
        
        /**
         * @author: ErnestFei
         * @date: 2018/5/27 19:28 
         * @Description: 插入数据并返回主键参数值
         */
        private long executeAndGetGeneratedKey(final DataSource dataSource, final String sql) throws SQLException {
            long result = -1;
            try (
                    Connection conn = dataSource.getConnection();
                    Statement statement = conn.createStatement()) {
                statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
                ResultSet resultSet = statement.getGeneratedKeys();
                if (resultSet.next()) {
                    result = resultSet.getLong(1);
                }
            }
            return result;
        }
    

    至此可看出在分库策略上sharding-jdbc做的流程,可将通过user_id定位到制定规则的数据库中,并在插入数据时进行动态分配数据源的数据,从而将数据均分落地到到两个库所对应的克隆的实际表中,实现分库操作。该example是通过直接取模分配数据源,当然我们也可以通过自己定的分片规则算法进行实现分片操作。具体的实现流程说明下篇继续tfyy。。。

    相关文章

      网友评论

        本文标题:sharding-sphere学习(1)之-[raw-examp

        本文链接:https://www.haomeiwen.com/subject/jdxijftx.html