背景
我们为什么要进行分库分表?
在电商系统中,当一张表的数据达到几千万时,查询一次所花的时间会变长。这时候,如果有联合查询的话,可能会卡死在那儿,甚至把系统给拖垮。而分库分表的目的就在于此:减小数据库的负担,提高数据库的效率,缩短查询时间。权衡过多个框架的利弊后,我们最终选择使用Sharding-JDBC来进行分库分表。
Sharding-JDBC简介
Sharding-jdbc定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据。
从官网的架构图中,可以看出我们只需要将Sharding-JDBC引入到项目中就好了。
Sharding-JDBC的使用
接下来,以b2b2c电商系统Javashop为例,具体说明sharding jdbc的应用:
一、分库分表的准备
在修改配置文件之前,我们应该想好我们的分片策略,包括:
1、要用几个数据库来分片
2、相应的表要分几张表
在本次分库分表中,以es_order表为例,将原始数据库javashop拆分为javashop0,javashop1两个数据库。将原始es_order表拆分为es_order0,es_order1两张表。
表中分片字段如下:
CREATE TABLE `es_order0` ( `order_id` bigint(20) NOT NULL COMMENT '主键ID', `trade_sn` varchar(20) DEFAULT NULL COMMENT '交易编号', 其他字段略) CREATE TABLE `es_order1` ( `order_id` bigint(20) NOT NULL COMMENT '主键ID', `trade_sn` varchar(20) DEFAULT NULL COMMENT '交易编号', 其他字段略)
二、引入maven依赖
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.0</version> </dependency>
三、配置分片策略
定义数据库的分片策略application.yaml:
spring: profiles: include: order #分库分表配置 shardingsphere: #配置sql是否显示输出,调试用,生产环境需关闭 props: sql: show: true sharding: #定义默认数据源为:ds0 default-data-source-name: ds0 #定义分库的数据源 datasource: #这里配置所有数据源的名字 names: ds0,ds1 ds0: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://ip:3306/default_database?useUnicode=true&characterEncoding=utf8&autoReconnect=true username: root password: 123456 ds1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.2.110:3306/javashop02?useUnicode=true&characterEncoding=utf8&autoReconnect=true username: root password: 123456
定义表分片策略修改application-order.yml:
spring: #分库分表配置 shardingsphere: sharding: tables: #交易表(用trade sn 分库,用trade_id分表) es_trade: actual-data-nodes: ds$->{0..1}.es_trade$->{0..1} database-strategy: inline: sharding-column: trade_sn algorithm-expression: ds$->{ new Long(trade_sn) % 2} table-strategy: inline: sharding-column: trade_id algorithm-expression: es_trade$->{trade_id % 2}
通过上述方式我们分别将商品,会员,订单进行了分库分表。
问题与解决方案
如果您以为就是这么简单就完成了那么就大错特错了。我们遇到的问题如下:
主键自增问题
因为当使用分库分表等功能之后,就不能再依赖数据库自带的主键生成机制了,一方面主键ID不能重复,另外需要在新增之前就知道主键ID,才能保证ID能够均匀分布到不同的数据库或数据表中,所以要使用一个合理的主键生成策略。
我们的解决方案就是在做insert语句的时候,使用snowflake发号器生成主键。snowflake 是常见的id(编号)生成算法,由时间戳+业务id+机器id+序列号组合而成,在电商系统中,用于订单号的生成、支付单号的生成等等。本发号器主要解决在容器化的部署情况时,自动扩容时保持机器id的唯一性。关于snowflake详细说明请看《java 商城系统源码分享-snowflake发号器》的文章
统一封装的insert方法如下:
public void insert(String table, Object po) { Long id = snCreator.create(getSubCode(table)); //设置刚刚主键值到 thread local lastIdThreadLocal.set(id); Map poMap = new HashedMap(); ColumnMeta columnMeta = ReflectionUtil.getColumnMeta(po); poMap.put(columnMeta.getPrimaryKeyName(), id); //这里就是将插入的时候使用雪花发号器作为主键,您们可以根据自己的业务进行修改。 如下略: }
使用snowflake发号器带来的类型问题
因为雪花发号器的类型为Long类型我们在未分库分表之前数据库使用的id类型为int(11),所以我们需要将所有涉及到分库分表id类型类型修改为bigint(20)。当然还有java代码中接收数据的实体类。
使用snowflake号器带来的精度丢失问题
因为js支持数字的最大精度为16位以下,那么我们的雪花发号器的位数为17为。好尴尬啊,后来我们统一将Long类型的数据转为String类型。代码如下:
@Configuration public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer customJackson() { return new Jackson2ObjectMapperBuilderCustomizer() { @Override public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) { //定义Long型的Json 值转换,转换为String型 //为了适配javascript 不支持Long型的精度 jacksonObjectMapperBuilder.serializerByType(Long.class,new JsonSerializer(){ @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(String.valueOf(value)); } }); } }; } }
使用相同字段进行分库分表的问题
相同字段进行分库分表,就是我们用主键id进行分库,然后再用主键id进行分表。如果我插入100条订单数据的话,那么javashop0数据库中es_order0表有50条id为奇数的数据es_order1表中的数据为0条。javashop1数据库中的es_order0表0条数据es_order1表中50条数据。这显然不是我们所希望看到的。所以我们在分库的时候使用与2取模的形式分库,分表的时候我们将id右移2位在此进行与2取模。那么得到的结果才是我们想要的。具体配置如下:
spring: #分库分表配置 shardingsphere: sharding: tables: #商品表(用member_id分库,用member_id分表) es_member: actual-data-nodes: ds$->{0..1}.es_member$->{0..1} database-strategy: inline: sharding-column: member_id algorithm-expression: ds$->{member_id% 2} table-strategy: inline: sharding-column: member_id #因为都是使用同一个字段进行分库分表的, #所以要右移两位之后取模以保证每个表中的数据平均 algorithm-expression: es_member$->{(member_id>>2)% 2}
Sharding-jdbc不支持的sql
官网提供不支持的sql如下:
sql语句 | 原因 |
INSERT INTO tbl_name (col1, col2, …) VALUES(1+2, ?, …) | VALUES语句不支持运算表达式 |
INSERT INTO tbl_name (col1, col2, …) SELECT col1, col2, … FROM tbl_name WHERE col3 = ? | INSERT … SELECT |
SELECT COUNT(col1) as count_alias FROM tbl_name GROUP BY col1 HAVING count_alias > ? | HAVING |
SELECT * FROM tbl_name1 UNION SELECT * FROM tbl_name2 | UNION |
SELECT * FROM tbl_name1 UNION ALL SELECT * FROM tbl_name2 | UNION ALL |
SELECT * FROM ds.tbl_name1 | 包含schema |
SELECT SUM(DISTINCT col1), SUM(col1) FROM tbl_name | 详见DISTINCT支持情况详细说明 |
SELECT * FROM tbl_name WHERE to_date(create_time, ‘yyyy-mm-dd’) = ? | 会导致全路由 |
SELECT SUM(DISTINCT col1), SUM(col1) FROM tbl_name | 同时使用普通聚合函数和DISTINCT聚合函数 |
这个问题的话我们的解决方案是优化我们的sql,将这些不支持的sql语句使用其他的逻辑实现在这里就不一一阐述了。
易族智汇(javashop)原创文章
相关推荐
CRMEB系统就是集客户关系管理+营销电商系统,能够快速积累客户、会员数据分析、智能转化客户、有效提高销售、会员维护、网络营销的一款企业应用,包含商城、拼团、砍价、秒杀、优惠券、积分、分销等功能。...
开篇词讲怎样才能做好性能调优02讲如何制定性能调优策略04讲...索引的失效与优化36讲什么时候需要分表分库37讲电商系统表设计优化案例分析39讲答疑课堂:MySQL中InnoDB的知识点串讲加餐讲推荐几款常用的性能测试工具
Z+ E 142.06 关于搜索技术的介绍& H, z8 Q3 } F 143.07 solr文本型缓存数据库搜索web应用平台的介绍 144.08 关键字项目搭建 145.09 solr启动# b6 A& c6 v7 M 146.10 solr库和表的创建 l- K' R4 c( a6 W# I2 M 147....
购物系统轻松管理维护,经济效率实实在在看得见。如不会本机调试本系统,请查看《IIS安装使用说明书》 网络电子商务网站在线购物系统源码正式版前台功能栏目 本系统包含的栏目功能有,最新商品,商品上架,商品...
经公司CIO反复调研,决定选用先电云计算平台搭建云计算平台和大数据系统应用研发。 搭建私有云平台,以实现资源的池化弹性管理、企业应用的集中管理、统一安全认证和授权管理。按照给出的云平台架构进行IaaS、PaaS、...
tiny在中文7情感分类数据集OCEMOTION上进行微调从而完成7分类情感分析模型的搭建,并基于PyQt5完成了最终中文微情感分析系统的开发,支持单条和批量文本细粒度情感分类预测,具有前沿性和广泛的应用价值。...
分库分表:Sharding 负载均衡:Nginx 消息中间件:RabbitMq 搜索引擎:ElasticSearch 数据库连接池: Druid 定时任务:xxl-job 对象存储: OSS、MINIO 全局事务管理框架:Seata 应用容器引擎: Docker 可视化D
A、文字处理软件和数据库管理系统 B、操作系统和数据库管理系统 C、系统软件和应用软件 D、程序和数据 14、( )不属于内存储器 A、高速缓冲存储器 B、RAM C、ROM D、CD-ROM 15、在Windows 7的系统工具中,( )可以...
A、文字处理软件和数据库管理系统 B、操作系统和数据库管理系统 C、系统软件和应用软件 D、程序和数据 14、( )不属于内存储器 A、高速缓冲存储器 B、RAM C、ROM D、CD-ROM 15、在Windows 7的系统工具中,( )可以...
A、文字处理软件和数据库管理系统 B、操作系统和数据库管理系统 C、系统软件和应用软件 D、程序和数据 14、〔〕不属于存储器 A、高速缓冲存储器B、RAM C、ROM D、CD-ROM 15、在Windows 7的系统工具中,( )可以将...
Excel商务数据分析与应用-期末试卷(含答案) Excel商务数据分析与应用-期末试卷(含答案)全文共9页,当前为第1页。Excel商务数据分析与应用-期末试卷(含答案)全文共9页,当前为第1页。《Excel商务数据分析与应用》期末...
MySQL基于关系型数据库模型,数据以表格形式组织,并通过预定义的键(如主键、外键)在表之间建立关联。它完全支持结构化查询语言(SQL),允许用户进行数据查询、插入、更新、删除、创建和管理数据库结构等操作。...
A、文字处理软件和数据库管理系统 B、操作系统和数据库管理系统 C、系统软件和应用软件 D、程序和数据 14、〔 〕不属于内存储器 A、高速缓冲存储器 B、RAM C、ROM D、CD-ROM 15、在Windows 7的系统工具中,( )可以...
MoChat 是开源的企业微信应用开发框架&引擎,是一套通用的企业微信多租户SaaS管理系统,得益于 Swoole 和 Hyperf 框架的优秀,MoChat 可提供超高性能的同时,也保持着极其灵活的可扩展性。 应用场景 可用于电商、...
项目后端服务器是基于node、mongodb开发,运行前请确认系统已安装相关应用 npm install 安装依赖 将web-serve/db/cate-shop文件夹下的数据导入到Mon - 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是...
机器学习的核心思想是让计算机系统通过学习数据中的模式和规律来实现目标,而不需要显式地编程。 机器学习应用非常广泛,包括但不限于以下领域: 图像识别和计算机视觉: 机器学习在图像识别、目标检测、人脸识别...
MySQL基于关系型数据库模型,数据以表格形式组织,并通过预定义的键(如主键、外键)在表之间建立关联。它完全支持结构化查询语言(SQL),允许用户进行数据查询、插入、更新、删除、创建和管理数据库结构等操作。...
人工智能AI:计算机视觉-日常物品实时图像分类...智能零售与电商:在商店或线上购物平台中,模型可以识别货架上的商品,实现自动结账、库存管理和个性化推荐。顾客可以通过手机扫描商品,快速获取商品信息和购买建议。
机器学习的核心思想是让计算机系统通过学习数据中的模式和规律来实现目标,而不需要显式地编程。 机器学习应用非常广泛,包括但不限于以下领域: 图像识别和计算机视觉: 机器学习在图像识别、目标检测、人脸识别...