精华内容
下载资源
问答
  • 在开发项目的时候我们通常会遇到这么一个问题,比如商城项目有一下单逻辑,下单成功数据保存在数据库中,下单成功后需要用户进行支付,如果在30分钟内支付失败,需要修改订单的支付状态为“支付超时”并关闭订单以及...

    学习使用,老鸟飞过,欢迎评论交流

    为什么要用到延迟队列

    在开发项目的时候我们通常会遇到这么一个问题,比如商城项目有一下单逻辑,下单成功数据保存在数据库中,下单成功后需要用户进行支付,如果在30分钟内支付失败,需要修改订单的支付状态为“支付超时”并关闭订单以及回退库存操作,那如何在下单30后准时检查支付结果处理订单状态呢?

    你可能想到了一个最简单的方法,就是使用定时任务扫描订单表,判断时间是否支付超时,这样的方式无疑是一种很消耗性能的做法,你试想一下,定时扫描一张数据量很大的表去判断时间和状态,而且99%的扫描都是无效的操作。

    那么该如何优雅的解决上述问题呢?我们可以采用延迟队列来实现,Redis和MQ都可以做到,本文章采用RabbitMQ的延迟队列来实现。

    延迟队列实现原理

    说到延迟队列就要说一说消息的过期时间(存活时间)TTL,RabbitMQ可以给队列设置过期时间,也可以单独给每个消息设置过期时间,如果到了过期时间消息没被消费该消息就会标记为死信消息。

    除此之外还有那些消息会成为死信消息?

    • 一是设置了TTL的消息到了TTL过期时间还没被消费,会成为死信
    • 二是消息被消费者拒收,并且reject方法的参数里requeue是false,意味这这个消息不会重回队列,该消息会成为死信,
    • 三是由于队列大小限制,新的消息进来队列可能满了,MQ会淘汰掉最老的消息,这些消息可能会成为死信消息

    成为死信的消息会进入一个死信交换机(Dead Letter Exchange)中,死信交换机也是一个普通的交换机而已,根据这一特点,我们可以准备一个队列来接收死信交换机中的死信消息,然后准备一个消费者来消费该队列中的消息,这样一来我们的延迟队列就有思路了,还是按照订单为例流程如下:
    在这里插入图片描述

    1. 下单成功(生产者),加入下单消息到队列(order.message)
    2. 队列设置TTL过期时间(10000毫秒),同时指定了死信交换机“delay-exchange”和死信交换机转发消息的队列“delay-message”
    3. 消息进入队列,等待一段时间,如果TTL时间到,订单消息会被MQ扔给死信交换机,死信交换机会把消息扔给指定的死信队列delay-message
    4. 消费者正好监听了死信队列delay-message,就可以获取到消息进行消费,比如检查该消息对应的订单是否支付,做出退库存处理等。

    整体效果就是,消息进入order.message队列 延迟 10秒后就 会进入delay-message队列然后被消费者消费处理,这就是一个延迟队列的效果。

    注意,这里的delay-exchange死信交换机其实就是一个普通的交换机而已,所以我们可以把上面的两个交换机合并成一个,如下:
    在这里插入图片描述

    延迟队列实战

    第一步,你需要集成RabbitMQ,我这里使用的是SpringBoot集成MQ

    <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    第二步,对MQ做一些配置

    spring:
      rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest
        virtualHost: /
    

    第三步,定义交换机和队列

    import org.springframework.amqp.core.*;
    import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
    import org.springframework.amqp.support.converter.MessageConverter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.HashMap;
    import java.util.Map;
    
    //rabbitMQ的配置
    @Configuration
    public class MQConfig {
        //交换机
        public static final String EXCHNAGE_DELAY = "EXCHNAGE_DELAY";
        //订单队列,该队列中的消息设置过期时间
        public static final String QUEUE_ORDER = "QUEUE_ORDER";
        //该队列用来接收死信交换机转发过来的消息
        public static final String QUEUE_DELAY = "QUEUE_DELAY";
        //队列的路由键,该路由键用来接收订单消息传出到订单队列
        public static final String ROUTINGKEY_QUEUE_ORDER = "ROUTINGKEY_QUEUE_ORDER";
        //该路由键用来接收死信交换机转发过来的消息
        public static final String ROUTINGKEY_QUEUE_DELAY = "ROUTINGKEY_QUEUE_DELAY";
    
        //定义交换机
        @Bean
        public Exchange exchangeDelay(){
            return ExchangeBuilder.topicExchange(EXCHNAGE_DELAY).durable(true).build();
        }
        //该队列中的消息需要设置ttl
        @Bean(QUEUE_ORDER)
        public Queue queueOrder(){
            Map<String,Object> map = new HashMap<>();
            map.put("x-dead-letter-exchange", EXCHNAGE_DELAY);    //过期的消息给哪个交换机的名字
            map.put("x-dead-letter-routing-key", ROUTINGKEY_QUEUE_DELAY);   //死信交换机把消息个哪个个routingkey
            map.put("x-message-ttl", 10000);    //队列过期时间10s
            return new Queue(QUEUE_ORDER,true,false,false,map);
        }
        //该队列接收死信交换机转发过来的消息
        @Bean(QUEUE_DELAY)
        public Queue queueDelay(){
            return new Queue(QUEUE_DELAY,true);
        }
        @Bean
        public Binding queueOrderBinding(){
            return BindingBuilder.bind(queueOrder()).to(exchangeDelay()).with(ROUTINGKEY_QUEUE_ORDER).noargs();
        }
        @Bean
        public Binding queueDelayBinding(){
            return BindingBuilder.bind(queueDelay()).to(exchangeDelay()).with(ROUTINGKEY_QUEUE_DELAY).noargs();
        }
        @Bean
        public MessageConverter messageConverter(){
            return new Jackson2JsonMessageConverter();
        }
    }
    

    第四部,写一个消息发送者

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = MQApplication.class)
    public class Producer {
    
        @Autowired
        private RabbitTemplate rabbitTemplate ;
    
       
    
        @Test
        public void sendDelayMessage() throws InterruptedException {
            System.out.println("发送消息:我是一个延迟消息,开始时间:"+System.currentTimeMillis());
            rabbitTemplate.convertAndSend(
                    MQConfig.EXCHNAGE_DELAY,
                    MQConfig.ROUTINGKEY_QUEUE_ORDER,
                    "我是一个延迟消息"
            );
    
            Thread.sleep(20000);
        }
    }
    

    第五步,写一个消费者

    @Component
    public class Consumer {
    
        @RabbitListener(queues = MQConfig.QUEUE_DELAY)
        public void handler(String message){
            System.out.println("收到消息:"+message+",结束时间:"+System.currentTimeMillis());
        }
    }
    

    第六步,测试效果

    • 生产者执行后,观察MQ,QUEUE_ORDER中有消息
      在这里插入图片描述

    • 等待10s之后,消息进入QUEUE_DELAY队列在这里插入图片描述

    • 控制台打印效果

    Producer:   发送消息:我是一个延迟消息,开始时间:1606295976347
    Consumer: 收到消息:我是一个延迟消息,结束时间:1606295986418
    

    发送消息到收到消息的时间差为 10071 , 忽略网络开销,延迟时间差不多就是我们设置的TTL时间

    文章结束,希望对你有所帮助

    展开全文
  • 第一种方法:增加新的逻辑去处理这个异常,比如打开的文件不存在,我们就增加一个判断语句,判断文件是否存在。但是如果有更多的问题出现,那么就需要增加更多的逻辑,我们可以知道这种方法并不高明。 第二种方法...
  • 关于如何对待NPE(NullPointerException)问题 关于如何处理NPE问题,我至今...如果不了解Optional可以查询一下.Optional类的代码非常简洁,但它的设计逻辑非常棒 情况1:对象为空时,需要给它默认值 Integer a = nul...

    关于如何对待NPE(NullPointerException)问题

    关于如何处理NPE问题,我至今没有定论.仅说说自己浅薄的看法
    JAVA的Optional工具类非常方便的处理NPE,但处理NPE不是代码的问题,是对业务设计规范的问题
    如果不了解Optional可以去查询一下.Optional类的代码非常简洁,但它的设计逻辑非常棒

    情况1:对象为空时,需要给它默认值

    Integer a = null;
    Optional.ofNullable(a).orElse(0)
    

    上面代码意思就是当a为不为空时返回a,否则返回默认值0,这里提一下orElseorElseGet的异同,从效果上没区别,但是性能有区别,orElseGet的意思在需要返回默认值时才去获取它(优化了性能).

    情况2:对象为空时,代码无法往下执行了

    Optional.ofNullable(obj).orElseThrow(customException)
    
    • 这种情况非常常见,解决方法应该是抛出异常,我们可以使用orElseThrow将NPE转换为业务级异常,当然也可以使用断言的方式,
    • 或许读者可能会疑惑尽管不做任何处理NPE也会被抛出的,但是笔者认为这样的处理方式,是一种行为规范,即重视对象的NPE问题.以及需要考虑对象为什么会为空(什么条件下为空),
    • 作为业务级设计来讲,如果不去思考情况2,那么可能就得不出需要使用情况3的结论.
    • 当然作为情况2读者也可以不做任何处理,我这里将它定义为隐式的情况2处理方式

    情况3:对象为不为空时,代码才执行

    Optional.ofNullable(query).ifPresent(p->p.hashCode());
    

    这种情况一般用于对对象以及对象相关的修饰处理,在业务上有就处理,没有就不处理的业务逻辑.

    展开全文
  • 今天给大家普及下如何用好企业邮箱?如何让领导先处理你的邮箱提高你的工作效率? 第一招:主题简短明确 想象你的邮箱里躺着上百封的邮件,你会先处理哪封呢?大多数人的答案应该是标题。一封能直指对方所关心问题的...

    进入公司分配了个TOM企业邮箱,职场萌新对于邮箱的概念仅存在QQ邮箱注册游戏的账号收验证码的层次。今天给大家普及下如何用好企业邮箱?如何让领导先处理你的邮箱提高你的工作效率?

    第一招:主题简短明确

    想象你的邮箱里躺着上百封的邮件,你会先处理哪封呢?大多数人的答案应该是标题。一封能直指对方所关心问题的邮件更吸引阅读者的兴趣。无主题邮件不要发,这是缺乏商务礼仪的表现。

    第二招:内容简洁逻辑严明

    邮件内容要分项罗列,简洁明了,几分钟内可了解情况,尊重双方的时间。长篇大论的邮件,没有人会认真去看。如果内容较多且复杂,需要更长的时间才能说清楚,可通过电话或者面对面会议。

    第三招:词汇使用

    邮件内容重点突出要恰当,慎用颜色和标注,避免错误的解读。另外温馨提示:禁用感叹号。

    以上是3点商务邮件处理注意事项,其实企业邮箱还有很多实用的功能,邮件撤回、误删恢复、微信收发、电子名片、超大附件、无限容量、国际通道、群组部门管理等功能,给企业员工带来了更便利的使用体验。

    展开全文
  • 弹出框了databean后如何返回值

    千次阅读 2011-06-30 11:37:00
    相信很多朋友在开发弹出框时,一些比较复杂的逻辑如果fld的东西实现会很难完成。这个时候大部分都会选择databean的方式,在execute()中做一些复杂逻辑处理。但是,这个时候又有一个新问题,我如果要像fld...

           相信很多朋友在开发弹出框时,一些比较复杂的逻辑如果用fld的东西去实现会很难完成。这个时候大部分都会选择databean的方式,在execute()中做一些复杂逻辑的处理。但是,这个时候又有一个新问题,我如果要像fld那样给源字段赋值,如何获取到?

           解决方法如下:

           在initialize()方法里:

           ControlInstance sourceControl = clientSession.getCurrentEvent().getSourceControlInstance();

           在execute()方法里:

           DataBean sourceDataBean = clientSession.getDataBean(sourceControl.getProperty("datasrc"));

           源mbo:

           MboRemote mbo = sourceDataBean .getmbo();
       

    展开全文
  • MR任务和普通的JAVA进程不太一样的地方是:它们是将jar包等搬到YARN上(MR的资源调度平台)执行的。调试起来有些地方就不太懂了。 最近自己摸索了下,用于解决如下两个场景,将其跑通: 1.在提交MR任务后,跟踪MR...
  • 了一个自己觉得不太优雅的算法去处理: ``` let listBackUp=[] let cityBackUp=[] let haveCity=false list.forEach((item,i)=>{ haveCitem=false citemBackUp=[] item.citys.forEach((citem...
  • acfly的基本逻辑是,你先把传感器注册上,然后它会有函数自动判断你传感器的数据质量如何,并选择什么传感器。 还有问题默认注册的位置传感器的数据单位是多少。 传感器的处理逻辑...
  • 故障定位的逻辑分析方法

    千次阅读 2008-02-11 14:52:00
    专家们在故障定位时的思考过程是...将定位问题的知识表达成逻辑结构形式的知识库,再运用计算机强大的逻辑处理能力,计算机来辅助定位的设想是可以实现的。而问题的关键就是如何简洁的表达复杂的知识。按照系统论的
  • 所以做法是,改一下项目的处理逻辑 一行代码搞定 然后就是跳转页面 注销之后跳转应该跳转到哪个页面呢?应该首页 跳转即可 总结 1、注销其实就是session的应用 2、转发和重定向我们哪个?一般情况下需要...
  • ),这个问题用手算也是可以解得唯一解的,logistic达到78%命中率就上不了,不论怎么调整样本集和初始截距,但是knn和神经网络都能训练到100% 模型的预测结果是一个四列的0~1之间的数值( 比如 [ 0.02222, 0.011111,...
  • 文章目录线程属性面试问题 线程属性面试问题 什么时候需要设置守护线程?...不同的操作系统,对于优先级的映射和调度都不一样, 很有可能优先级被操作系统所忽略, 所以不应该优先级去处理业务逻辑. ...
  • 背景: 随着业务的增加,我们服务器需要计算大量的用户数据,导致用户跟客服反应页面不能正常展示。反馈给开发后,我们一看,是服务器异常的错误。... 需要定义好网络失败后是如何跳转到重载页(R)的(wx.
  • ​ jquery的优点:他是常用的js工具方法的一堆封装,他在一定程度上加快前端...Jquery描述业务场景,而不是试图代码逻辑来解决问题。所以很多人就此对jquery造成依赖。很多提问的时候问,这个问题用jquery怎么...
  • 如何修改QT键值映射

    2020-08-21 10:09:08
    最近做一个嵌入式QT项目,当用户按设备上个...但这两种方法都有同一个问题,就是如果我有文本框控件,这时用户按了小键盘的1,虽然我可以捕获这个键值去处理自己的逻辑,但我却无法阻止文本编辑器上输入了个1,当然...
  • 2.2.4 实际中如何用哈尔或沃尔什函数构建图像变换矩阵? 58 2.2.5 哈尔变换的基元图像看起来是什么样的? 61 2.2.6 可以定义元素仅为+1 或.1 的正交矩阵吗? 65 B2.5 对沃尔什函数的排列方式 65 2.2.7 哈达玛/...
  • 在开发一个类微博系统,采用推模式,用户发一条微博,需要将此微博在其所有粉丝每人的“收件箱“中存一条,如果粉丝数量大,处理过程就会很耗时,想把这个逻辑用异步队列来实现。思路如下:1)用户每发一条微博,就...
  • 比如提交文件之后在提交表单,提交数据根据是否成功然后做出其他逻辑处理。kotlin里面提出协程概念,利用语法糖来解决这个问题。在javaScript里面也有async/await来使异步起来像同步。而在java中我暂时没有找到该...
  • 其实说多了也只是泪,按照本来的我正常的逻辑都是这样的:upload组件,选择图片的时候就会立刻上传到指定的地址,最多也...经过多次的尝试(掉了很多的头发),终于发现了如何去处理这个问题了。下面介绍主角: 上传
  • 在员工或者报表人员编辑完毕报表或者请假条的时候,点击提交实现持久化(这个容易),同时要发送到他需要发送到的地方。 比如员工A是财务部的,他整理好的报表信息需要发送给他们的经理审核。如果他们的经理在线...
  • 数据报表一直是后台产品的重要组件,相较于复杂的业务处理逻辑来讲算是非常简单了,简单到我们都不乐意花太多的时间审视它。现实情况却是:PRD整好交给开发后,开发又抛来各种问题,上线后的功能可以满足业务需求...
  • 我们是采用枚举的手法去处理数据,让模糊,随机,有噪声,不完全的数据先变成干净的嘛?比如说:“数据缺失可以忽略,可以均值,中值,可以决策树,贝叶斯逻辑推理数据”。那么如何批判数据处理的优劣?换句话说...
  • 如果做持续监听一直不处理线程的话 可行吗...总感觉会非常影响性能 同样的原理,想做一个复读机功能,大致逻辑想要:群员复读了10次之后,跟着复读1次。这似乎不可避免地需要监听每条...
  • 业务逻辑 给一段代码给站长,站长放到他的网站,然后访客访问站长的网站,我们的代码会自动判断访客是否为移动端,如果是,就跳转到指定页面,并且记录跳转的次数。(要区分这段代码是属于哪个站长的,属于哪个广告...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 501
精华内容 200
关键字:

如何用逻辑去处理问题