任务调度框架-如何实现定时任务+RabbitMQ事务+手动ACK

任务调度框架

Java中如何实现定时任务?

比如:
1.每天早上6点定时执行
2.每月最后一个工作日,考勤统计
3.每个月25号信用卡还款
4.会员生日祝福
5.每隔3秒,自动提醒

10分钟的超时订单的自动取消,每隔30秒或1分钟查询一次订单,拿当前的时间上前推10分钟
定时任务,资源会有误差的存在,如果使用定时任务
定时任务,用于统计的时候最多。

自动统计考勤,一般0点之后开始统计,可以使用定时任务

nacos心跳

晚上要求和采购部门生成采购单,达到最低预警值的时候,去发给采购部门

我们可以通过任务调度框架实现上述的需求
任务调度框架,可以实现定时任务,实现间隔多少时间的重复执行,实现指定日期的重复执行

电商自动好评,间隔时间长的,误差几分钟,影响不大。

java中任务调度框架:
1、Spring Task spring自带的
2、Quartz 古老的框架
3、XXL-Job
4、第三方云平台-比如说:阿里云-SchedulerX等等
选择一个:Spring Task
2个注解+
包:task任务、job

使用步骤:
1、开关类,使用注解
@EnableScheduling // 开启任务调度
在这里插入图片描述
2、定义定时任务

@Scheduled(cron = "0/3 * * * ?")

CORN表达式:
秒 分 时 日 月 星期几 年 其中,只有年可以省略
定时任务,需要重复执行的方法

CORN表达式:
特殊字符串,主要用来描述时间的,用于任务调度等
https://cron.qqe2.com/

/ 间隔
- 是连续
, 枚举值
L 最后,星期、日中用
W 有效工作日
LW 某个月最后一个工作日
# 用于确定每个月第几个星期几,母亲节或父亲节
4#2 某个月的第二个星期三  4代表星期三,中文的时候有可能不影响

在这里插入图片描述

在这里插入图片描述

项目名:SpringTask01
Spring Web、Lombok

RabbitMq实现延迟:

死信+延迟消息处理

死信:RabbitMQ的队列中的消息,满足以下条件任意其一就会成为死信消息:
1.消息被拒绝
2.消息过期
3.队列满了
死信交换器:专门用来转发队列中的死信消息,将死信消息转发到指定的队列中

十分钟未支付,取消订单?
十分钟之后,消息会过期,过期后,通过死信交换器转发队列中的死信消息,将死信消息转发到指定的队列中,由消费者去处理。

我们可以通过死信+死信交换器实现延迟消息处理
RabbitMQ实现延迟消息处理有2种方式:
1、死信+死信交换器 代码实现(可控,更方便一些)
2、延迟消息插件

1、死信+死信交换器 代码实现(可控,更方便一些)
发送消息,到队列1,(产生延迟队列,产生死信)
在这里插入图片描述
一个消息,过一段时间,实现消费。

核心:
1.队列 是2个队列,第1个队列: 目的 产生死信(1.设置有效期2.不设置消费者),借助死信交换器,把产生的死信发到指定的队列中
第二个对了:目的 消费死信,这里获取的信息,时间就是延迟的,延迟的就是上面的有效期
2.1个交换器
死信交换器,整个系统一般就一个,可以用来转发各个功能产生的死信,是Direct类型的交换,通过RK进行消息匹配到对应的队列中。
RabbitMQ的消息的有效期有2种设置方式:
1.设置队列上的有效期,整个队列中所有消息都使用
2.可以在每个消息上设置有效期,这种适用于有多个不同有效期的消息

在这里插入图片描述
如果队列和消息都有有效期,谁短听谁的。

代码:
RabbitMQ02
实现:
1.pom

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--        RabbitMQ --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency></dependencies>

2.代码:
config-RabbitMQConfig

package com.yd.rabbitmq02.config;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;/*** @author MaoXiqi* @organization: Lucky* @create 2023-10-16 11:35:54* @description RabbitMQConfigApi*/
@Configuration
public class RabbitMQConfig {// 1.创建2个队列@Beanpublic Queue createQ1() {// 1.设置队列 内部消息有效期 设置死信交换器 设置RKHashMap<String, Object> params = new HashMap<>();// 设置队列中每个消息的有效期 单位 毫秒params.put("x-message-ttl", 3000);// 设置对应的死信交换器params.put("x-dead-letter-exchange", "dead-ex-yd");// 设置交换器匹配的路由名称params.put("x-dead-letter-routing-key", "test");return QueueBuilder.durable("dl-q01").withArguments(params).build();}@Beanpublic Queue createQ2() {return new Queue("dl-q02");}// 2.创建1个交换器(1.fanout 2,direct 3.topic 4.header)-死信交换器direct类型@Beanpublic DirectExchange createDe() {return new DirectExchange("dead-ex-yd");}// 3.创建1个绑定@Beanpublic Binding createBd1(DirectExchange de) {return BindingBuilder.bind(createQ2()).to(de).with("test");}
}

在这里插入图片描述

2.1.创建两个队列
1、设置队列,内部消息有效期 设置死信交换器 设置RK 注意:参数名是固定的,值根据业务需求去改,值 单位是毫秒

2.2创建1个交换器(1.fanout 2.direct 3.tipic
4.header)-死信交换器direct类型

2.3.创建一个绑定

controller-DeadController

    @GetMapping("send")public String sendDead(String msg) {System.out.println("发送消息," + msg + ",发送时间:" + System.currentTimeMillis());template.convertAndSend("", "dl-q01", msg);return "ok";}

发送
在这里插入图片描述
监听消息-主要是为了消费:
listener-DeadListener

    @RabbitListener(queues = "dl-q02")public void handler(String m) {System.out.println("延迟消息,"+m+",接受时间:" +System.currentTimeMillis());}

在这里插入图片描述
yml:

spring:rabbitmq:host: 121.36.5.100port: 5672username: guestpassword: guest
server:port: 8082

测试:
在这里插入图片描述

RabbitMQ事务:

数据库中事务:保证数据一致性,特别是多个操作要么都成功,要么都失败
RabbitMQ事务:一次性发多条消息,需要开启事务,
RabbitMQ也有自己的事务,如果本次在这里插入图片描述

在这里插入图片描述

使用步骤:

源码:RabbitMQ02
1.创建配置类
2.使用基于事务发送
3.监听消息

1.创建配置类
config-RabbitMQTranConfig
1.准备一个队列
2.创建事务管理器

// 创建事务管理器@Beanpublic RabbitTransactionManager createTran(ConnectionFactory factory) {return new RabbitTransactionManager(factory);}

在这里插入图片描述

2.controller-TranController
开启事务
发送消息

    // 事务@Transactional // 需要开启SpringBoot的事务机制@GetMapping("sendmsg")public String sendMsg(String msg, int count) {// 开启 RabbitMQ的通道的事务template.setChannelTransacted(true);// 发送消息for (int i = 0; i < count; i++) {template.convertAndSend("", "yd-tran-q01", msg + "--" + count);// 出错,看看 事务是否生效if (i==2) {System.out.println(1/0);}}return "ok";}

在这里插入图片描述

3.listener-DeadListener

    // 事务@RabbitListener(queues = "yd-tran-q01")public void handler2(String msg) {System.out.println("监听消息"+msg);// 处理业务逻辑 出错了}

在这里插入图片描述

在这里插入图片描述

手动ACK

RabbitMQ怎么防止消息丢失:
1.发送端没有发送过去
解决:
1.用事务
2.confirm消息确认机制 万能:转人工处理
2.MQ服务器丢失,MQ服务器蹦了,
解决:开启持久化
3.消费端消息丢失:
解决:自动应答,改成开始手动ACK

消息确认机制:默认是自动确认

消息的发送和接收是异步

RabbitMQ如何防止消息丢失:
1.
代码:
config-RabbitMqTranConfig

    //消费消息的⼿动应答@Beanpublic Queue createQ4() {return new Queue("yd-ack-q01");}

controller-DeadController

    // 事务@Transactional // 需要开启SpringBoot的事务机制@GetMapping("sendmsg")public String sendMsg(String msg, int count) {// 开启 RabbitMQ的通道的事务template.setChannelTransacted(true);// 发送消息for (int i = 0; i < count; i++) {template.convertAndSend("", "yd-tran-q01", msg + "--" + count);// 出错,看看 事务是否生效if (i==2) {System.out.println(1/0);}}return "ok";}

listener-DeadListener
一般设置个上限,比如最多三次

    @RabbitListener(queues = "yd-ack-q01")public void handler3(String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {//消费者获取消息,默认采用的自动应答,就是获取就应答,这样MQ服务器就删除消息//还可以手动应答:结果:1.成功(MQ删除)2.失败(MQ消息)System.out.println("收到ACK消息,监听消息:" + msg);//拒绝消息 参数说明:1.消息id 2.结果 true 成功 false 拒绝 3.是否把消息添加回队列中channel.basicNack(tag,false,true);//成功消息 参数说明:1.消息id 2.结果 true 成功 false 拒绝//channel.basicAck(tag,true);// 处理业务逻辑 出错了}

在这里插入图片描述
在这里插入图片描述

消费消息的手动应答:
RabbitMQ默认的消费者消息获取模式采用的是手动应答
但是这种有缺陷,可能会出现,消息获取了但是业务出了问题,导致MQ也自动删除了消息,最终导致业务没有执行
所以为了解决这种问题,可以开启手动应答模式,结合自己的业务执行情况,如果业务执行成功,那么就成功应答,如果失败了,就拒绝消息,同时把消息再加回队列,这样就可以再次消息再次处理(加个上限)
在这里插入图片描述
测试
在这里插入图片描述

RabbitMQ如何保证消息的幂等性:
幂等性就是重复消费。
解决:
1.生成一个全局id,存入redis或者数据库,在消费者消费消息之前,查询一下该消息是否有小费过。
2.
在这里插入图片描述

用户充值,重复消费,相当如充值了多次,是一定要杜绝的。

在这里插入图片描述

不要返回值的时候,可以用RabbitMQ替代OpenFegin,因为消费完就不回了。MQ默认是单向的
短信发信可以用MQ,这个业务要做,做起来可能会很耗时,中间要经过运营商,过程不可控

RabbitMQ应用场景
消息通信,发送消息和接收消息,是异步
1.实现服务通信
用在微服务中,实现2个服务的通信,这种不带返回值的,只是为了执行另一个服务的方法执行
2.解决耗时操作
比如:邮件、短信、第三方接口等,比较耗时
3.解耦
4.提升性能
5.重复代码封装
6.削峰填谷(订单先下到redis中,再通过MQ和延迟队列,慢慢的从redis搬到mysql中)

关键词:异步、解耦、延迟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/112237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis在分布式场景下的应用

分布式缓存 缓存的基本作用是在高并发场景下对应服务的保护缓冲 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题&#xff1a; redis由于高强度性能采用内存 但是意味着丢失的风险单结点redis并发能力有限分布式服务中数据过多 依赖内存的redis 明显单机不…

微信小程序自定义组件及投票管理与个人中心界面搭建

14天阅读挑战赛 人生本来就没定义&#xff0c;任何的价值都是自己赋予。 目录 一、自定义tabs组件 1.1 创建自定义组件 1.2 tabs.wxml 编写组件界面 1.3 tabs.wxss 设计样式 1.4 tabs.js 定义组件的属性及事件 二、自定义组件使用 2.1 引用组件 2.2 编写会议界面内容 …

DTI综述(更新中)

Deep Learning for drug repurposing&#xff1a;methods&#xff0c;datasets&#xff0c;and applications 综述读完&#xff0c;觉得少了点东西&#xff0c;自己写个DTI综述 Databases(包括但不限于文章中的) DATABASEDESCRIBEBindingDB有详细的drug信息和对应的target&a…

推荐《中华小当家》

《中华小当家&#xff01;》 [1] 是日本漫画家小川悦司创作的漫画。该作品于1995年至1999年在日本周刊少年Magazine上连载。作品亦改编为同名电视动画&#xff0c;并于1997年发行播出。 时隔20年推出续作《中华小当家&#xff01;极》&#xff0c;于2017年11月17日开始连载。…

简单秒表设计仿真verilog跑表,源码/视频

名称&#xff1a;简单秒表设计仿真 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 秒表显示最低计时为10ms&#xff0c;最大为59:99&#xff0c;超出返回00&#xff1a;00 具有复位、启动、暂停三个按键 四个数码管分别显示4个时间数字。 演示…

LCR 177. 撞色搭配

LCR 177. 撞色搭配 LCR 177. 撞色搭配 迷你游戏之寻找两个单身狗 int* sockCollocation(int* sockets, int socketsSize, int* returnSize) {int* arr (int*)malloc(2 * sizeof(int));int ret 0;for (int i 0; i < socketsSize; i){ret ^ sockets[i];}int pos 0;for…

【七:docken+jenkens部署】

一&#xff1a;腾讯云轻量服务器docker部署Jenkins https://blog.csdn.net/qq_35402057/article/details/123589493 步骤1&#xff1a;查询jenkins版本&#xff1a;docker search jenkins步骤2&#xff1a;拉取jenkins镜像 docker pull jenkins/jenkins:lts步骤3&#xff1a;…

python -pandas -处理excel合并单元格问题

对于合并的单元格&#xff0c;不进行处理情况下&#xff0c;会默认输出nan问题 解决方法&#xff1a; class A(object):def __init__(self, xlsx_file_path, sheet_index):self.xlsx_file FileDataProcesser.read_excel(xlsx_file_path, sheet_index)self.sheet_data self.…

GitLab使用webhook触发Jenkins自动构建

1、jenkins安装gitlab插件 在插件管理中&#xff0c;搜索gitlab安装这个插件。 2、job中配置webhook地址和密钥 进入job设置&#xff0c;构建触发器中就可以看到gitlab的webhook配置&#xff0c;复制URL地址和随机令牌至gitlab中 勾选后&#xff0c;就可以展开设置&#xff…

代码随想录算法训练营第五十五天 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

300.最长递增子序列 视频讲解&#xff1a;动态规划之子序列问题&#xff0c;元素不连续&#xff01;| LeetCode&#xff1a;300.最长递增子序列_哔哩哔哩_bilibili 代码随想录 &#xff08;1&#xff09;代码 674. 最长连续递增序列 视频讲解&#xff1a;动态规划之子序列问题…

YOLOv5-调用官方权重进行检验(目标检测)

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营-第7周&#xff1a;咖啡豆识别&#xff08;训练营内部成员可读&#xff09; &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https…

点云处理【四】(点云关键点检测)

第一章 点云数据采集 第二章 点云滤波 第二章 点云降采样 1.点云关键点是什么&#xff1f; 关键点也称为兴趣点&#xff0c;它是2D图像、3D点云或曲面模型上&#xff0c;可以通过定义检测标准来获取的具有稳定性、区别性的点集。 我们获得的数据量大&#xff0c;特别是几十万…

【MySQL】数据库——表操作

文章目录 1. 创建表2. 查看表3. 修改表修改表名add ——增加modify——修改drop——删除修改列名称 4. 删除表 1. 创建表 语法&#xff1a; create table 表名字 ( 列名称 列类型 ) charset set 字符集 collate 校验规则 engine 存储引擎 ; charset set字符集 &#xff0c;若…

Java设计模式 | 基于订单批量支付场景,对策略模式和简单工厂模式进行简单实现

基于订单批量支付场景&#xff0c;对策略模式和简单工厂模式进行简单实现 文章目录 策略模式介绍实现抽象策略具体策略1.AliPayStrategy2.WeChatPayStrategy 环境 使用简单工厂来获取具体策略对象支付方式枚举策略工厂接口策略工厂实现 测试使用订单实体类对订单进行批量支付结…

景联文科技语音数据标注:AUTO-AVSR模型和数据助力视听语音识别

ASR、VSR和AV-ASR的性能提高很大程度上归功于更大的模型和训练数据集的使用。 更大的模型具有更多的参数和更强大的表示能力&#xff0c;能够捕获到更多的语言特征和上下文信息&#xff0c;从而提高识别准确性&#xff1b;更大的训练集也能带来更好的性能&#xff0c;更多的数据…

网工内推 | 金融业,网络管理岗,CCIE优先,最高30k

01 国民养老保险 招聘岗位&#xff1a;网络管理岗 职责描述&#xff1a; 1.负责公司整体网络架构规划、设计&#xff0c;制定整体网络方案&#xff0c;完善网络拓扑架构标准化文档&#xff0c;对公司现有网络进行梳理及持续优化。 2.负责公司网络系统建设&#xff0c;建立具备…

macos 12 支持机型 macOS Monterey 更新中新增的功能

macOS Monterey 能让你以全然一新的方式与他人沟通联络、共享内容和挥洒创意。尽享 FaceTime 通话新增的音频和视频增强功能&#xff0c;包括空间音频和人像模式。通过功能强大的效率类工具&#xff08;例如专注模式、快速备忘录和 Safari 浏览器中的标签页组&#xff09;完成更…

9月,1Panel开源面板项目收到了这些评论

2023年9月27日&#xff0c;1Panel开源面板项目&#xff08;https://github.com/1Panel-dev&#xff09;发布了题为《当1Panel开源项目被社区平台推荐后&#xff0c;我们收获了这些评论》的社区评论合集&#xff0c;在该文章的评论区&#xff0c;很多社区用户跟帖发表了自己对1P…

【Java】Java 11 新特性概览

Java 11 新特性概览 1. Java 11 简介2. Java 11 新特性2.1 HTTP Client 标准化2.2 String 新增方法&#xff08;1&#xff09;str.isBlank() - 判断字符串是否为空&#xff08;2&#xff09;str.lines() - 返回由行终止符划分的字符串集合&#xff08;3&#xff09;str.repeat(…

C进阶-语言文件操作

本章重点&#xff1a; 什么是文件 文件名 文件类型 文件缓冲区 文件指针 文件的打开和关闭文件的顺序读写文件的随机读写文件结束的判定 1. 什么是文件 磁盘上的文件是文件。 但是在程序设计中&#xff0c;我们一般谈的文件有两种&#xff1a;程序文件、数据文件 1.1 程序文件…