需求:

分库:按业务线business_id将不同业务线的订单存储在不同的数据库上;

分表:按user_id字段将不同用户的订单存储在不同的表上,为方便直接用非分片字段order_id查询,可使用基因法;

读写分离:为缓解主库的压力,读操作访问从库;

库表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

        <!-- sharding-jdbc -->
<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-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下的所有订单都含有相同基因,落在同一个表上。

资料:https://mp.weixin.qq.com/s/PCzRAZa9n4aJwHOX-kAhtA

根据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位基因片

小结

数据分片:

  • 支持分库+分表;
  • 可支持 = , BETWEEN,IN等多维度分片,也支持多分片键共用;
  • 支持聚合,分组,排序,分页,关联等复杂查询语句;
  • 分片灵活,支持多分片键共用,支持inline表达式;
  • 基于Hint的强制路由;
  • 支持分布式主键

读写分离:

  • 支持一主多从的读写分离;
  • 支持分库分表与读写分离共同使用
  • 支持分布式生成全局主键。

柔性事务:

  • 最大努力到达型事务

分布式治理:

  • 支持配置中心,可动态修改
  • 支持客户端熔断和失效转移

引用:http://shardingsphere.io/

sharing-jdbc实现读写分离及分库分表的更多相关文章

  1. spring boot sharding-jdbc实现分佈式读写分离和分库分表的实现

    分布式读写分离和分库分表采用sharding-jdbc实现. sharding-jdbc是当当网推出的一款读写分离实现插件,其他的还有mycat,或者纯粹的Aop代码控制实现. 接下面用spring ...

  2. mycat+mysql集群:实现读写分离,分库分表

    1.mycat文档:https://github.com/MyCATApache/Mycat-doc       官方网站:http://www.mycat.org.cn/ 2.mycat的优点: 配 ...

  3. Mycat数据库中间件对Mysql读写分离和分库分表配置

    Mycat是一个开源的分布式数据库系统,不同于oracle和mysql,Mycat并没有存储引擎,但是Mycat实现了mysql协议,前段用户可以把它当做一个Proxy.其核心功能是分表分库,即将一个 ...

  4. MyCat读写分离、分库分表

    系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理本身优化也是非常重要的.主从.热备.分表分库等都是系统发展迟早会遇到的技术问题问题.Mycat是一 ...

  5. Mycat实现读写分离、分库分表

    系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理本身优化也是非常重要的.主从.热备.分表分库等都是系统发展迟早会遇到的技术问题问题.Mycat是一 ...

  6. Mysql之Mycat读写分离及分库分表

    ## 什么是mycat ```basic 1.一个彻底开源的,面向企业应用开发的大数据库集群 2.支持事务.ACID.可以替代MySQL的加强版数据库 3.一个可以视为MySQL集群的企业级数据库,用 ...

  7. Tbase读写分离与分库分表

    一.读写分离 1.1 what 读写分离 读写分离,基本的原理是让主数据库处理事务性增.改.删操作(INSERT.UPDATE.DELETE),而从数据库处理SELECT查询操作.数据库复制被用来把事 ...

  8. mysql主从读写分离,分库分表

    1.分表 当项目上线后,数据将会几何级的增长,当数据很多的时候,读取性能将会下降,更新表数据的时候也需要更新索引,所以我们需要分表,当数据量再大的时候就需要分库了. a.水平拆分:数据分成多个表 b. ...

  9. Ameba读写分离_mycat分库分表_redis缓存

    1 数据库的读写分离 1.1 Amoeba实现读写分离 1.1.1 定义 Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy 优点: 配置读写分离时较为简单.配置 ...

随机推荐

  1. java框架之SpringBoot(9)-数据访问及整合MyBatis

    简介 对于数据访问层,无论是 SQL 还是 NOSQL,SpringBoot 默认采用整合 SpringData 的方式进行统一处理,添加了大量的自动配置,引入了各种 Template.Reposit ...

  2. Cocos2d-js3.3 模态对话框的实现

    首先,先了解一下什么是模态对话框,百度百科的给出了下面一个定义: 模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话 ...

  3. C++ Windows API 读写INI文件

    BOOL WritePrivateProfileString( LPCTSTR lpAppName, // INI文件中的一个字段名[节名]可以有很多个节名 LPCTSTR lpKeyName, // ...

  4. #WEB安全基础 : HTTP协议 | 0x5 URI和URL

    URI(统一资源标识符)和URL(统一资源定位符)相信大家都知道URL吧,我们看看它们有什么区别 URI 长得就像这样 /images/hackr.jepg URL 长得像这样 http://hack ...

  5. java之连接数据库之JDBC访问数据库的基本操作

    1.将数据库的JDBC驱动加载到classpath中,在基于JavaEE的web应用实际开发过程中通常要把目标数据库产品的JDBC驱动复制到WEB—INF/lib下. 2.加载JDBC驱动并将其注册到 ...

  6. EasyUI相关知识点整理

    EasyUI相关知识整理 EasyUI是一种基于jQuery.Angular..Vue和React的用户界面插件集合.easyui为创建现代化,互动,JavaScript应用程序,提供必要的功能.也就 ...

  7. 安装JDK并配置环境变量以及Hello World

    摘要:本文主要说明在Windows环境下JDK的安装,以及安装完成之后环境变量的配置,并通过DOS运行简单的Java程序. 安装JDK 说明 SDK:软件开发工具包(Software Developm ...

  8. Html 标签初知

    Html 标签初知 什么是Html 标签 超文本标记语言(外国语简称:HTML)标记标签通常被称为HTML标签,HTML标签是HTML语言中最基本的单位,HTML标签是HTML(标准通用标记语言下的一 ...

  9. Codeforces 333E Summer Earnings - bitset

    题目传送门 传送门I 传送门II 传送门III 题目大意 给定平面上的$n$个点,以三个不同点为圆心画圆,使得圆两两没有公共部分(相切不算),问最大的半径. 显然答案是三点间任意两点之间的距离的最小值 ...

  10. .NET 实用扩展方法

    .NET 实用扩展方法(持续更新...) 1. 字符串转换为可空数值类型(int, long, float...类似) /// <summary> /// 将字符串转换成32位整数,转换失 ...