线上订单号重复了?一招搞定它!

springboot+poi导出百万级数据避免OOM内存溢出 记录下在实际项目中碰到过一个重大问题,全量导出百万级数据,由于之前在开发环境数据没有达到百万级别,因此此问题没有处理,上到测试环境后,数据量达到150万的时候,全量导出所有的数据出现内存溢出问题。这段代码亲测有效,到测试环境上导出五百多万条数据都没有出现OOM问题,希望对各位朋友有效。这里实现了多个sheet页导出的数据,excel导出一个sheet最多能导出100万多一点数据,至于具体数字,请朋友们自行百度下。 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:blog.youkuaiyun.com/xk4848123/
article/details/105427680/


问题的背景

公司老的系统原先采用的时间戳生成订单号,导致了如下情形

92617787005d316c32c85cdc7f883b2f.png 53403876d96aab7c89a63de35062712c.png

打断一下:大家知道怎么查系统某项重复的数据吧

SELECT * FROM XX表 WHERE 重复项 in( SELECT 重复项 FROM XX表 GROUP BY 重复项 HAVING count(1) >= 2)
“

推荐下自己做的 Spring Boot 的实战项目:

https://github.com/YunaiV/ruoyi-vue-pro

解决方法

不得了,这样重复岂不是一单成功三方回调导致另一单也成功了。

多个服务怎么保证生成的订单号唯一呢?

先上code

package com.zhongjian.util;

public class IdWorkerUtil{

    private long workerId;
    private long datacenterId;
    private long sequence;

    public IdWorkerUtil(long workerId, long datacenterId, long sequence){
        // sanity check for workerId
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
        }
        System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
                timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);

        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = sequence;
    }

    private long twepoch = 1288834974657L;

    private long workerIdBits = 5L;
    private long datacenterIdBits = 5L;
    private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    private long sequenceBits = 12L;

    private long workerIdShift = sequenceBits;
    private long datacenterIdShift = sequenceBits + workerIdBits;
    private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long lastTimestamp = -1L;

    public long getWorkerId(){
        return workerId;
    }

    public long getDatacenterId(){
        return datacenterId;
    }

    public long getTimestamp(){
        return System.currentTimeMillis();
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
                    lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;
        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen(){
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        IdWorkerUtil idWorkerUtil = new IdWorkerUtil(1,1,0L);
        System.out.println(idWorkerUtil.nextId());
    }

}
0a6aa3a35906ae9141f29c922336fc63.png

以上是采用snowflake算法生成分布式唯一ID

41-bit的时间可以表示(1L<<41)/(1000L360024*365)=69年的时间,10-bit机器可以分别表示1024台机器。如果我们对IDC划分有需求,还可以将10-bit分5-bit给IDC,分5-bit给工作机器。

这样就可以表示32个IDC,每个IDC下可以有32台机器,可以根据自身需求定义。12个自增序列号可以表示2^12个ID,理论上snowflake方案的QPS约为409.6w/s,这种分配方式可以保证在任何一个IDC的任何一台机器在任意毫秒内生成的ID都是不同的。

这种方式的优缺点是:

优点

  • 毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。

  • 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。

  • 可以根据自身业务特性分配bit位,非常灵活。

缺点

  • 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。

一般来说,采用这种方案就解决了。

还有诸如,mysql的 auto_increment策略,redis的INCR,zookeeper的单一节点修改版本号递增,以及zookeeper的持久顺序节点。

看完点个赞呗~



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

1ee2055263de2d5daaa83fce918ded81.png

已在知识星球更新源码解析如下:

a7dcf85ed19c7ad25e5f36b897ef41d4.png

23457fa2cf5233677d2d97fb8c031506.png

d524ede371ff19504567ec2553de13fb.png

d9292e93469c743c8d758b4aa1ea59ea.png

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
解决POI读取Excel内存溢出的问题 Office软件一直是一个诲誉参半的软件,广大普通计算机用户用Office来满足日常办公需求,于是就产生了很多生产数据和文档,需要和企业单位的专用办公系统对接,而Office的解析工作一直是程序员非常头痛的问题,经常招致程序员的谩骂,也被誉为是微软最烂的发明之一。POI的诞生解决了Excel的解析难题(POI即“讨厌的电子表格”,确实很讨厌,我也很讨厌Excel),但如果用不好POI,也会导致程序 阅读详情

相关推荐

从订单号补零到日志对齐:StringUtils的leftPad/rightPad/center,3个方法搞定所有格式化需求

本文详细介绍了Apache Commons Lang中StringUtils类的leftPad、rightPad和center方法,这些方法能高效解决订单号补零、日志对齐等文本格式化需求。通过电商、金融等实际场景案例,展示如何利用这三个方法提升系统专业性和用户体验,同时提供中英文混合处理、性能优化等进阶技巧。

806

图解电商支付架构设计,这才是真电商

点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 8:55 更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2020 超神之路,很肝~中...

芋艿V 907

若依框架导出Excel,如何优雅地合并相同订单号的行?一个注解搞定

本文详细介绍了如何在若依框架中利用`@Excel`注解实现Excel导出时合并相同订单号的行,提升报表的可读性和专业性。通过简单的配置,开发者可以轻松实现智能行合并功能,适用于订单管理、报表统计等业务场景。

weixin_32006655的博客 275

kafka-console-ui的简介及安装使用

kafka-console-ui 是一款轻量级的kafka可视化管理平台,安装、配置特别简单,一般来说只需要配置一个kafka集群地址启动即可。为了开发的省事,没有国际化支持,页面只支持中文展示。不是一个企业级的平台,目前看来只适合中、小型集群的管理。这个工具看起来是挺low的,但是对于刚接触kafka急需一个合适工具进行管理的同学来说,还是挺友好的,没有国际化支持,全是中文展示。支持broker相关配置的查看及修改。

初夏0811的博客 7420

微信小程序 - 详细实现随机生成订单号,微信小程序创建订单号思路,不重复订单号生成的方法,小程序自动生成固定规则的订单号流水号(必须是唯一不重复的订单号,生成唯一订单号)详细生成方法,示例代码教程最新

微信小程序,vue2,vue3,订单号,流水号思路,微信小程序 详细实现随机生成订单号(JavaScript),随机生成商户订单号,根据当前时间随机生成流水号或者订单号,微信小程序之商家订单,订单号随机生成器,自动生成固定规则的订单号(前缀+采购日期+6位流水号)微信小程序 生成外卖顺序号,生成订单号或流水号简单方法,实现订单号生成唯一的解决方案,如何按日期生成订单号,14位编号=8位日期(+6位流水号),自动生成订单号(固定+日期+数字),销售订单号自动生成。在微信小程序开发中,详解实现随机生成创建订单号

🏆 前端领域优质创作者 1189

解决poi读取excel2007出现内存溢出问题代码参

解决poi读取excel2007出现内存溢出问题代码参

别再写重复代码了!用Redis搞定每日重置的订单号/流水号生成(Spring Boot实战)

本文详细介绍了在Spring Boot中利用Redis实现高并发场景下的订单号/流水号生成方案。通过Redis的原子操作和内存计算特性,解决了传统数据库方案在分布式环境下的性能瓶颈,实现每日重置序号的需求,并提供了生产环境中的高可用配置和性能优化技巧。

weixin_26869081的博客 342

ANSYS材料库实战:手把手教你用APDL命令流定义混凝土和形状记忆合金

本文详细介绍了在ANSYS中使用APDL命令流定义混凝土和形状记忆合金(SMA)的高级建模技巧。通过SOLID65单元和SMA本构模型,工程师可以精确模拟非线性材料行为,包括混凝土的开裂和SMA的超弹性效应。文章提供了完整的命令流示例和求解策略优化建议,帮助用户提升工程仿真效率。

hh234的博客 486

如何在大促期间避免用户重复下单?一文教你搞定!

分布式锁是用来解决多服务、多线程同时访问共享资源的问题。它的目标是确保在分布式环境下,每个时刻只能有一个进程或线程在操作某一份数据,进而避免并发问题。在我们的场景中,分布式锁的作用就是确保多个重复的订单请求同时到达时,只有第一个请求可以成功生成订单,其他请求必须等待或者直接返回失败。

孤芳不自赏 1141

零基础玩转STM32CubeIDE LL库:5分钟搞定串口通信(附完整代码)

本文为零基础开发者提供了一份STM32CubeIDE LL库串口通信的快速实战指南。通过CubeMX配置、LL库核心API详解,以及中断接收与环形缓冲区的完整代码实现,帮助读者在5分钟内搭建稳定可靠的串口收发框架,解决从HAL切换到LL库的常见困惑,提升嵌入式开发效率。

weixin_29159441的博客 307

UE5.3与Colosseum配置实战:从编译到问题解决的全流程指南

本文提供了在Windows系统下配置UE5.3与Colosseum仿真环境的全流程实战指南。详细介绍了从软件版本选择、源代码获取、编译脚本执行到解决常见编译错误和引擎崩溃问题的具体步骤,旨在帮助开发者高效搭建无人机、机器人等仿真平台,并顺利运行外部API控制。

weixin_29002595的博客 557

从0到1搞定第三方支付接口!手把手教你5步打通线上收款通道​

而一个稳定、安全、便捷的第三方支付接口,不仅能提升用户体验,还能为商家降低技术开发成本、规避资金风险。​拆解第三方支付接口的开通过程,并附上避坑指南和实用建议,助你快速打通线上收款通道!在数字化浪潮下,无论是电商平台、在线教育还是本地生活服务,​。​双通道,覆盖90%以上用户;跨境业务需提前申请外汇资质。开通第三方支付接口并非终点,而是精细化运营的起点。​都是用户转化链条的最后一环,也是最关键的一环。​(如满减、红包)进一步提升转化。​:中小商户优先选择​。

hlkj123456的博客 2029

【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析

【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析

|~~~热爱生活、努力学习的小伙汁~~~| 2113
上一篇: 国产最强开源 MPP 数据库 StarRocks,没有之一,支持小红书百万日查询!
下一篇: 架构与思维:系统容量设计
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值