sharing-jdbc實現讀寫分離及分庫分表

需求:mysql

分庫:按業務線business_id將不一樣業務線的訂單存儲在不一樣的數據庫上;算法

分表:按user_id字段將不一樣用戶的訂單存儲在不一樣的表上,爲方便直接用非分片字段order_id查詢,可以使用基因法;spring

讀寫分離:爲緩解主庫的壓力,讀操做訪問從庫;sql

庫表SQL

複製代碼
-- 主庫
CREATE DATABASE `database_103`;
CREATE DATABASE `database_112`;

-- 從庫
CREATE DATABASE `database_slave_103`;
CREATE DATABASE `database_slave_112`;

--每一個庫上分別創建以下表
CREATE TABLE `t_order_0` (
  `id` bigint(20) NOT NULL,
  `order_id` bigint(20) NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `business_id` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `t_order_1` (
  `id` bigint(20) NOT NULL,
  `order_id` bigint(20) NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `business_id` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `t_order_2` (
  `id` bigint(20) NOT NULL,
  `order_id` bigint(20) NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `business_id` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t_order` VALUES (1,1,112);

CREATE TABLE `t_order_3` (
  `id` bigint(20) NOT NULL,
  `order_id` bigint(20) NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `business_id` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
複製代碼

pom.xml

按 Ctrl+C 複製代碼
按 Ctrl+C 複製代碼

spring-database.xml

複製代碼
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:rdb="http://www.dangdang.com/schema/ddframe/rdb"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx.xsd

                        http://www.dangdang.com/schema/ddframe/rdb
                        http://www.dangdang.com/schema/ddframe/rdb/rdb.xsd">

    <bean id="database_112" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="${jdbc.url.112}"></property>
        <property name="username" value="${jdbc.username.112}"></property>
        <property name="password" value="${jdbc.password.112}"></property>
        <property name="maxActive" value="100"/>
        <property name="initialSize" value="50"/>
        <property name="maxWait" value="60000"/>
        <property name="minIdle" value="5"/>
    </bean>

    <bean id="database_slave_112" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="${jdbc.url.slave.112}"></property>
        <property name="username" value="${jdbc.username.slave.112}"></property>
        <property name="password" value="${jdbc.password.slave.112}"></property>
        <property name="maxActive" value="100"/>
        <property name="initialSize" value="50"/>
        <property name="maxWait" value="60000"/>
        <property name="minIdle" value="5"/>
    </bean>

    <bean id="database_103" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="${jdbc.url.103}"></property>
        <property name="username" value="${jdbc.username.103}"></property>
        <property name="password" value="${jdbc.password.103}"></property>
        <property name="maxActive" value="100"/>
        <property name="initialSize" value="50"/>
        <property name="maxWait" value="60000"/>
        <property name="minIdle" value="5"/>
    </bean>

    <bean id="database_slave_103" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="${jdbc.url.slave.103}"></property>
        <property name="username" value="${jdbc.username.slave.103}"></property>
        <property name="password" value="${jdbc.password.slave.103}"></property>
        <property name="maxActive" value="100"/>
        <property name="initialSize" value="50"/>
        <property name="maxWait" value="60000"/>
        <property name="minIdle" value="5"/>
    </bean>

    <!--mybatis-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="mapperLocations" value="classpath:xmlmapper/*.xml"/>
        <property name="dataSource" ref="shardingDataSource"/>
        <!-- 配置Mybatis配置文件 -->
        <property name="configLocation" value="classpath:/mybatis/mybatis-config.xml"/>
    </bean>
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    <!-- 註解Mapper scanner -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.lc.sharding.mybatismapper"/>
        <property name="sqlSessionTemplateBeanName" value="sqlSession"/>
    </bean>

    <!-- 事務-->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="shardingDataSource"/>
    </bean>
    <tx:annotation-driven transaction-manager="txManager"/>
    <!--讀寫分離-->
    <rdb:master-slave-data-source id="rbb_112" master-data-source-ref="database_112"
                                  slave-data-sources-ref="database_slave_112"/>
    <rdb:master-slave-data-source id="rbb_103" master-data-source-ref="database_103"
                                  slave-data-sources-ref="database_slave_103"/>
    <!--分庫策略-->
    <rdb:strategy id="databaseShardingStrategy" sharding-columns="business_id"
                  algorithm-expression="rbb_${business_id.longValue()}"/>
    <!--分表策略-->
    <rdb:strategy id="tableShardingStrategy" sharding-columns="user_id,order_id"
                  algorithm-class="com.lc.sharding.algorithm.MultipleKeysTableShardingAlgorithmImpl"/>

    <rdb:data-source id="shardingDataSource">
        <rdb:sharding-rule data-sources="rbb_112,rbb_103">
            <rdb:table-rules>
                <rdb:table-rule logic-table="t_order" actual-tables="t_order_${0..3}" database-strategy="databaseShardingStrategy"
                                table-strategy="tableShardingStrategy"/>
            </rdb:table-rules>
        </rdb:sharding-rule>
        <rdb:props>
            <prop key="metrics.enable">true</prop>
            <prop key="sql.show">true</prop>
        </rdb:props>
    </rdb:data-source>
</beans
複製代碼

基因法多列分片

複製代碼
public class MultipleKeysTableShardingAlgorithmImpl implements MultipleKeysTableShardingAlgorithm {
    public Collection<String> doSharding(Collection<String> tableNames, Collection<ShardingValue<?>> shardingValues) {
        List<String> shardingSuffix = new ArrayList<String>();
        long partId = 0;
        for (ShardingValue value : shardingValues) {
            if (value.getColumnName().equals("user_id")) {
                partId = ((Long) value.getValue()) % 4;
                break;
            } else if (value.getColumnName().equals("order_id")) {
                partId = ((Long) value.getValue()) % 4;
                break;
            }
        }
        for (String name : tableNames) {
            if (name.endsWith(partId + "")) {
                shardingSuffix.add(name);
                return shardingSuffix;
            }
        }
        return shardingSuffix;
    }
}
複製代碼

什麼是基因法分片?數據庫

在訂單數據oid生成時,order_id末端加入分片基因,讓同一個user_id下的全部訂單都含有相同基因,落在同一個表上。express

資料:https://mp.weixin.qq.com/s/PCzRAZa9n4aJwHOX-kAhtAmybatis

根據user_id生成order_id:

複製代碼
    public long bulidOrderId(long userId) {
        //取用戶id後4位
        userId = userId & 15;
        //先取60位惟一id
        long uniqueId = this.nextId();
        //惟一id左移4位、拼接userId後4位
        return (uniqueId << 4) | userId;
    }
複製代碼
this.nextId();//使用雪花算法生成60位分佈式惟一id:1位符號位+41位時間戳+5位workId+5位datacenterId+6位序列號+4位基因片

 小結

數據分片:app

  • 支持分庫+分表;
  • 可支持 = , BETWEEN,IN等多維度分片,也支持多分片鍵共用;
  • 支持聚合,分組,排序,分頁,關聯等複雜查詢語句;
  • 分片靈活,支持多分片鍵共用,支持inline表達式;
  • 基於Hint的強制路由;
  • 支持分佈式主鍵

讀寫分離:分佈式

  • 支持一主多從的讀寫分離;
  • 支持分庫分表與讀寫分離共同使用
  • 支持分佈式生成全局主鍵。

柔性事務:ui

  • 最大努力到達型事務

分佈式治理:

  • 支持配置中心,可動態修改
  • 支持客戶端熔斷和失效轉移

引用:http://shardingsphere.io/

相關文章
相關標籤/搜索