分布式秒杀实战之订单数据分表
前言
一般来说电商的日订单都是百千万级甚至是亿万级别的了,小小的数据库肯定是撑不住的,这时候就要提前考虑分库分表了。
国内一般大厂规则参考:
- 单表500万条记录,正常水平
- 800万条警戒线
- 1000万条必须要分库分表
一般业界,对订单数据的分库分表,有两类思路:按照订单号来切分、按照用户id来切分,当然各有利弊,这里不细说。
手动分表
这个在秒杀一中已有体现,这里仅仅是分表而已,提供一种思路,供参考,测试的时候自行建表。
按照用户 ID
来做 hash
分散订单数据。为了减少迁移的数据量,一般扩容是以倍数的形式增加。比如原来是8个库,扩容的时候,就要增加到16个库,再次扩容,就增加到32个库。这样迁移的数据量,就小很多了。
这个问题不算很大问题,毕竟一次扩容,可以保证比较长的时间,而且使用倍数增加的方式,已经减少了数据迁移量。
String table = "success_killed_"+userId%8;
nativeSql = "INSERT INTO "+table+" (seckill_id, user_id,state,create_time)VALUES(?,?,?,?)";
Object[] params = new Object[]{seckillId,userId,(short)0,new Timestamp(System.currentTimeMillis())};
dynamicQuery.nativeExecuteUpdate(nativeSql,params);
手动撕业务逻辑是不是很low
?今天给大家推荐一款分表神器。
自动分表
墙裂推荐使用开源的分布式数据库中间件 ShardingSphere
,资料丰富,入手简单, 并且已于2020年4月16日成为 Apache
软件基金会的顶级项目,值得信赖。
适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
- 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
- 支持任意实现JDBC规范的数据库。目前支持 MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
集成 SpringBoot
案例使用 SpringBoot2.2.6.RELEASE + JPA
,部分坐标请自行引入。
引入坐标pom.xml
:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
配置文件 application.properties
:
server.port=8080
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.shardingsphere.datasource.names=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://localhost:3306/shardingsphere?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=root
spring.shardingsphere.datasource.ds.max-active=16
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds.t_order_$->{0..1}
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}
#自增列名称,缺省表示不使用自增主键生成器
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
#自增列值生成器类型,缺省表示使用默认自增列值生成器。可使用用户自定义的列值生成器或选择内置类型:SNOWFLAKE/UUID
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
#工作机器唯一id,默认为0,最大1024
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=6
定义实体类,项目启动会自动生成表,也可以手动创建表:
@Data
@Entity
@Table(name = "t_order")
public final class OrderEntity{
private static final long serialVersionUID = 4743102234543827854L;
/**
* 订单ID
*/
@Id
@Column(name = "order_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long orderId;
/**
* 商品ID
*/
@Column(name = "goods_id")
private long goodsId;
/**
* 用户ID
*/
@Column(name = "user_id")
private int userId;
/**
* 支付状态 1 支付完成 0 支付中
*/
@Column(name = "pay_status")
private short payStatus;
}
模拟订单插入:
@Api(tags ="订单管理")
@RestController
@RequestMapping("/order")
public class OrderControl {
@Autowired
private OrderRepository orderRepository;
/**
* 插入
*/
@PostMapping("/save")
public void save(){
for(int i=0;i<10;i++){
OrderEntity entity = new OrderEntity();
entity.setUserId(i);
entity.setGoodsId(1000L);
entity.setPayStatus((short)0);
orderRepository.save(entity);
}
}
}
模拟订单插入,执行请求,向数据库插入十条订单,查看数据库,如果表t_order_0
和t_order_1
分别有5条记录,说明配置成功。
小结
以上仅仅是一个小小的案例,大部分猿媛都不大可能接触电商实战,实际上业务极其复杂,复杂到小编都不敢轻易在这里吹牛逼。终其一生,很多公司的数据库可能还不过百万尔尔。
推荐
一款从0到1构建分布式秒杀系统,脱离案例讲架构都是耍流氓。
码址:gitee.com/52itstyle/spring-boot-seckill
- DedeCMS全版本通杀SQL注入漏洞利用代码及工具
- Android实现滑动刻度尺效果,选择身高体重和生日
- 浅谈开源web程序后台的安全性
- Web漏洞演练平台 – ZVulDrill
- Android内存泄漏终极解决篇(上)
- 走近科学:我是如何入侵Instagram查看你的私人片片的
- 在线手写识别的多卷积神经网络方法
- 苹果发布OS X 10.9.2更新,修复SSL漏洞
- Android内存泄漏终极解决篇(下)
- 利用Volatility查找系统中的恶意DLL
- 雪人行动:利用IE10 0day漏洞的APT攻击剑指美国军方情报
- Android开发:最详细的 Toolbar 开发实践总结
- 关于yubikey对web应用的杞人之忧
- 利用旧版Android漏洞的E-Z-2-Use攻击代码已在Metasploit发布
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法