重复提交优化:
- js层面,在用户点击提交订单后禁用按钮。
- 使用Redis incrde 原子性递增计数
//针对同一单生成固定唯一标识
orderNum=memberId+productId;
//条数加1
count = redis.increment(orderNum, 1); //添加过程中会返回当前总数
if (count == 1) {
//设置有效期2秒
redis.expire(orderNum, 2, TimeUnit.SECONDS);
}
if (count > 1) {
resultMap.put("retCode", "500");
resultMap.put("retMsg", "请不要重复提交订单");
return resultMap;
}
操作同一条数据优化
FOR UPDATE注意事项
- 在mysql中FOR UPDATE时,如果查询条件带有主键会锁行数据,如果没有则会锁表数据。
- 如果查询一条正在执行事务的数据时使用了FOR UPDATE 此时程序会进行阻塞,直到事务进行提交或者回滚时才会查询出结果。
FOR UPDATE使用场景
当商户取消某一个订单时,此时用户正在支付此笔订单,当程序运行到查询此笔【待支付】订单金额时需要使用 FOR UPDATE ,然而程序一直会阻塞,直到商户取消完订单【已取消】事务提交后,此时查询结果会显示查询订单不存在,避免了错误支付的情况。
大表数据查询
优化前:
聚簇索引:就是存放指向磁盘的叶子节点
慢的原因:需要查询300005次索引节点,查询300005次聚簇索引的数据,最后再将结果过滤掉前300000条,取出最后5条。MySQL耗费了大量随机I/O在查询聚簇索引的数据上,而有300000次随机I/O查询到的数据是不会出现在结果集当中的。
mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (15.98 sec)
优化后:
mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.38 sec)
快的原因:先沿着索引叶子节点查询到最后需要的5个节点,然后再去聚簇索引中查询实际数据。这样只需要5次随机I/O,
缓存层
- elasticsearch:搜索引擎、分布式日志存储
- redis:
- String : 分布式id、砍价(用户每天只能投票一次)、地区存储
- Hash:车三项、用户四要素
- List:朋友圈点赞按顺序展示、关注列表按照顺序展示
- Set:网站每日的IP访问数量、用户首次登陆推送喜欢的商品
- Sorted_set:排行榜
3 分库分表
分库
- 会涉及到分布式事务来保证数据的一致性
- 在生成唯一单号时要在中台服务生成供后台使用
分表
- 通过哈希算法均匀的分配到不同的表里面
- Mycat它是数据库中间件,可通过它来组织数据库的分离读写和分库分表,客户端通过它来访问下层数据库,还会涉及数据同步,数据一致性的问题。
水平拆分表
就是把一个表的数据拆分到多个库的多个表里面去。这里面的每个库的表结构都是一样的,只不过是表中存放的数据不一样,每个库表的数据汇总起来就是全部数据。
垂直拆分表
就是把一个有很多字段的表给拆分成多个表或者多个库上面去,每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会将较少的访问频率很高的字段放到一个表里面去,然后将较多的访问频率很低的字段放到另外一个表里面去。
分库分表实例
- 分销商城订单分库分表,拆分十个表分别为
order_1,order_2...
,订单详情表也要拆分,还要拆分两个库data_1,data_2
。 - 编号为0-4在
data_1
库,编号为5-9在data_2
库,订单服务的表只需要订单总表和订单详情表拆分,别的表只要一份,在对应的库里即可。 - 当用户下单购买时,以用户id最后一位为标准存到对应的库里的对应表里,并且在es里面维护一份数据方便运营端查询,es要存储这条数据属于哪个库里的哪张表
- 当订单状态发生改变时,也要同时维护es里的数据
- 当运营端统计订单总量时,只需要查询es即可分页、搜索,修改都支持