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));
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM