zoukankan      html  css  js  c++  java
  • sharding-jdbc 实现分表

    Sharding-JDBC 简介

    Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本:

    • 可适用于任何基于Java的ORM框架,如:JPA、HIbernate、MYbatis、Spring JDBC Template或者直接使用JDBC。
    • 可基于任何第三方的数据库连接池,如:DBCP、C3P0、Druid等。
    • 理论上可支持任意实现JDBC规范的数据库。目前支持MySQL、Oracle、SQLServer等。

    Sharding-JDBC定位为轻量级Java框架,使用客户端直连数据库,以jar包形式提供服务,未使用中间层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。采用“半理解”理念的SQL解析引擎,以达到性能与兼容性的最大平衡。

    Sharding-JDBC功能灵活且全面:

    • 分片策略灵活,可支持 = , BETWEEN,IN等多维度分片,也支持多分片键共用。
    • SQL解析功能完善,支持聚合,分组,排序,Limit,TOP等查询,并且支持Binding Table以及笛卡尔积的表查询。
    • 支持柔性事务(目前仅最大努力送达型)。
    • 支持读写分离。
    • 支持分布式生成全局主键。

    整体架构图


    sharding-JDBC 实现分表

    数据库表

    CREATE TABLE IF NOT EXISTS `t_order_0` (  
      `order_id` INT NOT NULL,  
      `user_id`  INT NOT NULL,  
      PRIMARY KEY (`order_id`)  
    ); 
    CREATE TABLE IF NOT EXISTS `t_order_1` (  
      `order_id` INT NOT NULL,  
      `user_id`  INT NOT NULL,  
      PRIMARY KEY (`order_id`)  
    ); 
    CREATE TABLE IF NOT EXISTS `t_order_2` (  
      `order_id` INT NOT NULL,  
      `user_id`  INT NOT NULL,  
      PRIMARY KEY (`order_id`)  
    ); 
    

    pom.xml

    <dependency>
        <groupId>com.dangdang</groupId>
        <artifactId>sharding-jdbc-core</artifactId>
        <version>1.4.2</version>
    </dependency>
    <dependency>
        <groupId>com.dangdang</groupId>
        <artifactId>sharding-jdbc-config-spring</artifactId>
        <version>1.4.0</version>
    </dependency>
    

    Spring配置

        <rdb:strategy id="tableShardingStrategy" sharding-columns="user_id" algorithm-expression="t_order_${user_id.longValue() % 3}"/>
    
        <rdb:data-source id="shardingDataSource">
            <rdb:sharding-rule data-sources="dataSource">
                <rdb:table-rules>
                    <rdb:table-rule logic-table="t_order" actual-tables="t_order_${0..2}"  table-strategy="tableShardingStrategy" />
                </rdb:table-rules>
            </rdb:sharding-rule>
        </rdb:data-source>
    

    单测

    直接对MyBatis Mapper进行测试。

    Order order = new Order();
    order.setOrderId(1111);
    order.setUserId(222);
    
    Boolean result = orderMapper.insert(order) > 0;
    
    System.out.println(result?"插入成功":"插入失败");
    

    OrderExample example = new OrderExample() ;
    example.createCriteria().andUserIdEqualTo(1112);
    
    List<Order> orderList = orderMapper.selectByExample(example) ;
    
    System.out.println(JSONObject.toJSONString(orderList));
    

    使用SingleKeyTableShardingAlgorithm 实现分表规则

    目标:每个业务线一个数据表(business_id:业务线Id)。

    自定义的分表规则类需要实现SingleKeyTableShardingAlgorithm,并重写doBetweenSharding、doEqualSharding、doInSharding。

    修改数据表

    ALTER TABLE `t_order_0` ADD business_id INT(4) ;
    ALTER TABLE `t_order_1` ADD business_id INT(4) ;
    ALTER TABLE `t_order_2` ADD business_id INT(4) ;
    
    ALTER TABLE `t_order_0` RENAME t_order_112; 
    ALTER TABLE `t_order_1` RENAME t_order_101; 
    ALTER TABLE `t_order_2` RENAME t_order_113; 
    

    重新生成Mybatis Mapper相关文件

    Spring 配置

        <rdb:strategy id="tableShardingStrategy" sharding-columns="business_id"  algorithm-class="com.boothsun.util.sharding.OrderSingleKeyTableShardingAlgorithm"/>
    
        <rdb:data-source id="shardingDataSource">
            <rdb:sharding-rule data-sources="dataSource">
                <rdb:table-rules>
                    <rdb:table-rule logic-table="t_order" actual-tables="t_order_${[112,101,113]}"  table-strategy="tableShardingStrategy" />
                </rdb:table-rules>
            </rdb:sharding-rule>
        </rdb:data-source>
    

    注意:这里使用的是algorithm-class而非algorithm-expression

    OrderSingleKeyTableShardingAlgorithm 具体实现

    /**
     * 每个业务线一个表
     */
    public class OrderSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer>  {
    
        /**
         * 对于分片字段的between操作都走这个方法。
         */
        public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) {
            Collection<String> result = new LinkedHashSet<>(tableNames.size());
            Range<Integer> range =  shardingValue.getValueRange();
            for (long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
                for (String each : tableNames) {
                    if (each.endsWith(String.valueOf(i))) {
                        result.add(each);
                    }
                }
            }
            return result;
        }
    
        /**
         * 对于分片字段的等值操作 都走这个方法。(包括 插入 更新)
         */
        public String doEqualSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) {
           String sdValue =  String.valueOf(shardingValue.getValue());
           for (String tableName : tableNames ) {
               if(tableName.endsWith(sdValue)) {
                   return  tableName ;
               }
           }
           throw  new IllegalArgumentException("无分表参数 无法定位具体数据表");
        }
    
        /**
         * 对于分片字段的in操作,都走这个方法。
         */
        public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) {
    
            Collection<String> result = new LinkedHashSet<>(tableNames.size());
    
            for (Integer value : shardingValue.getValues()) {
                for (String tableName : tableNames) {
                    if (tableName.endsWith(String.valueOf(value))) {
                        result.add(tableName);
                    }
                }
            }
            return result;
        }
    }
    

    单测类

    /**
     * 测试插入
     * @throws Exception
     */
    @Test
    public void insertSelective() throws Exception {
    
        Order order = new Order();
        order.setOrderId(123113);
        order.setUserId(222);
        order.setBusinessId(112);
    
        Boolean result = orderMapper.insert(order) > 0;
    
        System.out.println(result?"插入成功":"插入失败");
    }
    
    /**
     * 测试 in 的查询操作
     * @throws Exception
     */
    @Test
    public void selectByExample2() throws Exception {
    
        List<Integer> values = new ArrayList<>();
        values.add(112);
        values.add(113);
    
        OrderExample example = new OrderExample() ;
        example.createCriteria().andUserIdEqualTo(11333).andBusinessIdIn(values);
    
        List<Order> orderList = orderMapper.selectByExample(example) ;
    
        System.out.println(JSONObject.toJSONString(orderList));
    }
    
    /**
     * 测试between的查询操作
     * @throws Exception
     */
    @Test
    public void selectByExample3() throws Exception {
    
        OrderExample example = new OrderExample() ;
        example.createCriteria().andBusinessIdBetween(112,113);
    
        List<Order> orderList = orderMapper.selectByExample(example) ;
    
        System.out.println(JSONObject.toJSONString(orderList));
    }
    
    
  • 相关阅读:
    hadoopnamenode配置及问题处理方案
    hadoop 运行 Java程序
    hadoop命令大全
    DOS
    腾讯Linux QQ安装
    linux下安装realplayer
    在linux中配置安装telnet服务
    关于C#静态构造函数的几点说明
    linux下的Network File Server共享配置
    Oracle学习笔记
  • 原文地址:https://www.cnblogs.com/boothsun/p/7825853.html
Copyright © 2011-2022 走看看